﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Transactions;
using CrmContacto.Contracts;
using CrmContacto.Contracts.Contracts;
using CrmContacto.Contracts.Contracts.Misc;
using CrmContacto.Contracts.Contracts.Search;
using CrmContacto.Contracts.Enums;
using CrmContacto.Contracts.Services;
using CrmContacto.Data;
using CrmContacto.Services.Common;
using Web.Framework.Helpers;
using Web.Framework.Svc;
using Web.Framework.Translate;
using Web.Framework.Encrypt;
using Web.Framework.Mapper;
using Web.Framework.Enum;
using CrmContacto.Services.Classes;
using CrmContacto.Contracts.Promociones;
using CrmContacto.Services.Marketing;
using System.Linq.Expressions;
using LinqKit;
using Web.Framework.Validation;

namespace CrmContacto.Services
{
    public class CrmContactoAdminService : ICrmContactoAdminService
    {
        public List<CompanyConfiguration> GetCompanyConfigurations()
        {
            return ListsCrm.GetCompanyConfigurations();
        }

        public Dictionary<string, string> GetCompanyConfigurationKeyValues(int companyId)
        {
            return ListsCrm.GetCompanyConfigurationKeyValues(companyId);
        }

        //public List<MaestroBase> GetCampaniasActivas(int emrpesaId)
        //{
        //    return ListsCrm.GetCampaniasActivas( emrpesaId, null);
        //}       

        public List<MaestroBase> GetTipoDocumento(int paisId)
        {
            return ListsCrm.GetTipoDocumento(paisId);
        }

        public List<MaestroBase> GetProvincias(int paisId)
        {
            return ListsCrm.GetProvincias(paisId);
        }

        public List<MaestroBase> GetCategoriasDeContacto(MaestroBaseSearch searchMaestroBase)
        {
            return ListsCrm.GetCategoriasDeContacto(searchMaestroBase);
        }

        public List<ReportingConfiguration> GetReportingConfiguration(string name, int empresaId)
        {
            List<ReportingConfiguration> reportingConfigurationList = new List<ReportingConfiguration>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbReporte> query = ctx.DbReportes;

                query = query.Where(q => q.EmpresaId == empresaId);

                if (!String.IsNullOrEmpty(name))
                {
                    query = query.Where(r => r.Nombre == name);
                }

                query = query.OrderBy(r => r.MenuOrder);

                foreach (var c in query)
                {
                    ReportingConfiguration rc = new ReportingConfiguration();
                    rc.Nombre = c.Nombre;
                    rc.ReportPath = c.ReportPath;
                    rc.ReportUri = c.ReportingServer.Url;
                    rc.UserName = c.ReportingServer.UserName;
                    rc.Password = EncryptHelper.Decrypt(c.ReportingServer.Password, "crm");
                    rc.Domain = c.ReportingServer.Domain;
                    rc.SecurityKey = c.SecurityKey;
                    rc.LocalizationKey = c.LocaleKey;
                    rc.ReportAppUrl = c.ReportAppUrl;
                    reportingConfigurationList.Add(rc);
                }
            }

            return reportingConfigurationList;
        }

        public MaestroBase SaveCategoria(ServiceOptions options, MaestroBase categoria, int empresaId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbCategoria dbCategoria = ctx.DbCategorias.FilterLogicalRemoved().Where(c => c.Id == categoria.Id).SingleOrDefault();
                    if (dbCategoria == null)
                    {
                        dbCategoria = new DbCategoria();
                        ctx.DbCategorias.AddObject(dbCategoria);
                        dbCategoria.EmpresaId = empresaId;
                        dbCategoria.AuditFechaCreacion = DateTime.Now;
                        dbCategoria.AuditUserNameCreacion = options.UserName;
                    }
                    else
                    {
                        dbCategoria.AuditFechaModificacion = DateTime.Now;
                        dbCategoria.AuditUserNameModificacion = options.UserName;
                    }

                    dbCategoria.Nombre = categoria.Nombre;

                    ctx.SaveChanges();
                    tScope.Complete();
                    categoria.Id = dbCategoria.Id;
                }
            }

            return categoria;
        }

        public List<AccionDeMarketingPromocionRegla> GetReglasAccionDeMarketing(MaestroBaseSearch search)
        {
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                return ctx.DbAccionDeMarketingPromocionReglas.FilterLogicalRemoved().Where(e => e.EmpresaId == search.EmpresaId).Select(r => new AccionDeMarketingPromocionRegla()
                {
                    Id = r.Id,
                    Nombre = r.Nombre,
                    Descripcion = r.Descripcion,
                    EmpresaId = r.EmpresaId
                }).ToList();
            }
        }

        public AccionDeMarketingPromocionRegla SaveReglasAccionDeMarketing(ServiceOptions options, AccionDeMarketingPromocionRegla regla)
        {
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                var dbRegla = ctx.DbAccionDeMarketingPromocionReglas.Where(e => e.Id == regla.Id).SingleOrDefault();

                if (dbRegla == null)
                {
                    dbRegla = new DbAccionDeMarketingPromocionRegla();
                    ctx.DbAccionDeMarketingPromocionReglas.AddObject(dbRegla);
                    dbRegla.AuditFechaCreacion = DateTime.Now;
                    dbRegla.AuditUserNameCreacion = options.UserName;
                }

                EntityMapper.Map(regla, dbRegla, "Id");

                ctx.SaveChanges();
                regla.Id = dbRegla.Id;
            }

            return regla;
        }

        public void EliminarRegla(ServiceOptions options, int reglaId)
        {
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                var regla = ctx.DbAccionDeMarketingPromocionReglas.Where(r => r.Id == reglaId).SingleOrDefault();
                if (regla != null)
                {
                    var dbRegla = ctx.DbAccionDeMarketingPromocionReglas.Where(r => r.Id == reglaId).SingleOrDefault();
                    dbRegla.AuditFechaModificacion = DateTime.Now;
                    dbRegla.AuditUserNameModificacion = options.UserName;
                    dbRegla.Removed = true;
                    ctx.SaveChanges();
                }
            }
        }

        public void EliminarCategoria(ServiceOptions options, int categoriaId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbCategoria dbCategoria = ctx.DbCategorias.FilterLogicalRemoved().Where(c => c.Id == categoriaId).SingleOrDefault();
                    if (dbCategoria != null)
                    {
                        dbCategoria.AuditFechaModificacion = DateTime.Now;
                        dbCategoria.AuditUserNameModificacion = options.UserName;
                        dbCategoria.Removed = true;
                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public void EliminarContactos(ServiceOptions options, CustomerSearchParam searchParam)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    int total = 0;
                    IQueryable<DbContacto> query = GetCustomerSearchQuery(searchParam, ref total, ctx);
                    foreach (var contacto in query)
                    {
                        contacto.AuditFechaModificacion = DateTime.Now;
                        contacto.AuditUserNameModificacion = options.UserName;
                        contacto.Removed = true;
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }

            }
        }

        public List<MaestroBase> GetListasDeDistribucion(int empresaId)
        {
            return ListsCrm.GetListasDeDistribucion(empresaId);
        }

        public List<Producto> GetProductos(ServiceOptions options, ProductoSearch search)
        {
            List<Producto> productos = new List<Producto>();
            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                IQueryable<DbProducto> query = ctxCrm.DbProductoes.Where(p => p.EmpresaId == search.EmpresaId);

                if (!String.IsNullOrEmpty(search.Codigo))
                {
                    query = query.Where(c => c.Codigo.Contains(search.Codigo));
                }

                if (!String.IsNullOrEmpty(search.Nombre))
                {
                    query = query.Where(c => c.Nombre.Contains(search.Nombre));
                }

                foreach (var dbProducto in query.ToList())
                {
                    Producto producto = new Producto();
                    EntityMapper.Map(dbProducto, producto);
                    productos.Add(producto);
                }
            }

            return productos;
        }

        public ParticipantesSearchResult GetParticipantes(ServiceOptions options, ParticipantesSearch searchParam)
        {
            // Primero tengo que identificar la promocion y delegar la consulta de participantes            
            ParticipantesSearchResult result = new ParticipantesSearchResult();
            List<ParticipantePromocion> participantes = new List<ParticipantePromocion>();

            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                ctxCrm.CommandTimeout = 300;

                var promoStrategyList = MarketingPromocionesManager.Instance.GetPromocionesVigentes(searchParam.EmpresaId);
                var dbPromocion = ctxCrm.DbAccionDeMarketingPromocions.Where(p => p.Id == searchParam.PromocionId).Single();
                if (dbPromocion != null && promoStrategyList != null)
                {
                    var promoStrategy = promoStrategyList.Where(ps => ps.Nombre == dbPromocion.TipoImplementacion).SingleOrDefault();

                    // Una vez que sé la estrategia, delego la consulta para armar el query
                    result = promoStrategy.GetParticipantes(searchParam);
                }
            }

            return result;
        }

        public ClienteSearchResult GetCustomers(ServiceOptions options, CustomerSearchParam searchParam)
        {
            ClienteSearchResult result = new ClienteSearchResult();
            List<Cliente> clientes = new List<Cliente>();

            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                ctxCrm.CommandTimeout = 300;
                int totalDeResultados = 0;
                IQueryable<DbContacto> query = GetCustomerSearchQuery(searchParam, ref totalDeResultados, ctxCrm);

                result.TotalDeResultados = totalDeResultados;

                List<DbContacto> dbContactoList = query.ToList();

                result.PageIndex = searchParam.PageSkip;
                result.PageSize = searchParam.PageSize;

                foreach (DbContacto dbContacto in dbContactoList)
                {
                    Cliente registro = new Cliente();
                    if (searchParam.SoloInformacionBasica)
                    {
                        LoadCustomerVeryBasicInfo(dbContacto, registro);
                    }
                    else
                    {
                        LoadCustomerBasicInfo(ctxCrm, dbContacto, registro);
                    }
                    clientes.Add(registro);
                }
            }

            result.Resultados = clientes;

            return result;
        }

        private static IQueryable<DbContacto> GetCustomerSearchQuery(CustomerSearchParam searchParam, ref int totalDeResultados, CrmContactoEntities ctxCrm)
        {
            IQueryable<DbContacto> query;
            if (searchParam.IncludeRemoved)
            {
                query = ctxCrm.DbContactoes;
            }
            else
            {
                query = ctxCrm.DbContactoes.FilterLogicalRemoved();
            }

            query = query.Where(c => c.EmpresaId == searchParam.EmpresaId);

            // si buscan por clave solo uso ese parámetro
            if (searchParam.Ids.Count() > 0)
            {
                query = query.Where(c => searchParam.Ids.Contains(c.Id));
                searchParam.PageSkip = 0;
                searchParam.PageSize = 0;
            }
            else
            {
                if (searchParam.ConEmail.HasValue)
                {
                    if (searchParam.ConEmail.Value)
                    {
                        query = query.Where(c => c.Email != null && c.Email != string.Empty);
                    }
                    else
                    {
                        query = query.Where(c => c.Email == null || c.Email == string.Empty);
                    }
                }

                if (searchParam.ConDocumento.HasValue)
                {
                    if (searchParam.ConDocumento.Value)
                    {
                        query = query.Where(c => c.NroDocumento.HasValue);
                    }
                    else
                    {
                        query = query.Where(c => !c.NroDocumento.HasValue);
                    }
                }

                if (searchParam.ConVentas.HasValue)
                {
                    if (searchParam.ConVentas.Value)
                    {
                        query = query.Where(c => c.ContactoVenta.FechaUltimaCompra.HasValue);
                    }
                    else
                    {
                        query = query.Where(c => !c.ContactoVenta.FechaUltimaCompra.HasValue);
                    }
                }

                if (searchParam.CodigosProducto.Count > 0)
                {
                    StringBuilder builderProducto = new StringBuilder();

                    string separador = string.Empty;
                    foreach (string cp in searchParam.CodigosProducto)
                    {
                        builderProducto.Append(separador);
                        builderProducto.Append(cp.Replace(" ", ""));
                        separador = ",";
                    }

                    //searchParam.CodigoProducto = searchParam.CodigoProducto.ToUpper();
                    // Busco los id de clientes que compraron ese artículo
                    var contactoIds = ctxCrm.GetContactosQueCompraron(searchParam.EmpresaId, builderProducto.ToString()).ToList();
                    List<int> customerIdList = new List<int>();
                    foreach (var contactoId in contactoIds)
                    {
                        customerIdList.Add(contactoId.Value);
                    }

                    query = query.Where(c => customerIdList.Contains(c.Id));
                }

                if (!String.IsNullOrEmpty(searchParam.ProductoTemporadaLetra))
                {
                    query = query.Where(c => (from v in c.Ventas where v.TEMPORADA == searchParam.ProductoTemporadaLetra select 1).Any());
                }

                if (!String.IsNullOrEmpty(searchParam.ProductoCodigoColor))
                {
                    query = query.Where(c => (from v in c.Ventas where v.ITEM_COLOR == searchParam.ProductoCodigoColor select 1).Any());
                }

                if (!String.IsNullOrEmpty(searchParam.ProductoCodigoTalle))
                {
                    query = query.Where(c => (from v in c.Ventas where v.ITEM_SIZE == searchParam.ProductoCodigoTalle select 1).Any());
                }

                if (searchParam.AccionesDeMarketingList.Count > 0)
                {
                    // tengo que buscar los clientes que esten en estas listas de distribucion o en la cuponera de esta lista
                    query = query.Where(c => ((from cupo in c.AccionDeMarketingCupones where searchParam.AccionesDeMarketingList.Contains(cupo.AccionDeMarketingId) select 1).Any()) ||
                                             ((from cupo in c.AccionDeMarketingCupones1 where searchParam.AccionesDeMarketingList.Contains(cupo.AccionDeMarketingId) select 1).Any()) ||
                                             ((from lista in c.ListaDistribucions where (from accion in lista.AccionDeMarketings where accion.PlanDeMarketing.EmpresaId == searchParam.EmpresaId && searchParam.AccionesDeMarketingList.Contains(accion.Id) select 1).Any() select 1).Any())
                        );
                }

                if (searchParam.FechaCompraDesde.HasValue && searchParam.FechaCompraHasta.HasValue)
                {
                    var contactoIds = ctxCrm.GetContactosQueCompraronEntreFechas(searchParam.EmpresaId, searchParam.FechaCompraDesde, searchParam.FechaCompraHasta).ToList();
                    List<int> customerIdList = new List<int>();
                    foreach (var contactoId in contactoIds)
                    {
                        customerIdList.Add(contactoId.CONTACTO_ID);
                    }

                    query = query.Where(c => customerIdList.Contains(c.Id));
                }

                if (searchParam.Vendedores.Count > 0)
                {
                    query = query.Where(c => c.ContactoVentas.Where(p => searchParam.Vendedores.Contains(p.AuditUserNameCreacion)).Count() > 0);
                }

                if (searchParam.CreadoresDelContacto.Count > 0)
                {
                    query = query.Where(c => searchParam.CreadoresDelContacto.Contains(c.AuditUserNameCreacion));
                }

                if (searchParam.PuntosDeVenta.Count > 0)
                {
                    // Cambiar estas ventas por las totales
                    List<string> codigosPdv = ctxCrm.DbPuntoDeVentas.Where(pdv => searchParam.PuntosDeVenta.Contains(pdv.Id)).Select(pdv => pdv.CodigoExterno).ToList();

                    query = query.Where(c => c.ContactoVentas.Where(p => p.PuntoDeVentaId.HasValue && searchParam.PuntosDeVenta.Contains(p.PuntoDeVentaId.Value)).Count() > 0 ||
                                             (from v in c.Ventas where codigosPdv.Contains(v.POINT_OF_SALES_CODE) select 1).Count() > 0);
                }

                if (searchParam.OrigenPuntosDeVenta.Count > 0 && searchParam.OrigenContacto.Contains((int)TipoContactoOrigen.PuntoDeVenta))
                {
                    query = query.Where(c => searchParam.OrigenPuntosDeVenta.Contains(c.OrigenPuntoDeVentaId.Value));
                }

                if (searchParam.OrigenContacto.Count > 0)
                {
                    query = query.Where(c => searchParam.OrigenContacto.Contains(c.OrigenId));
                }

                if (searchParam.TiposDocumento.Count > 0)
                {
                    query = query.Where(c => c.TipoDocumentoId.HasValue && searchParam.TiposDocumento.Contains(c.TipoDocumentoId.Value));
                }

                if (searchParam.CumpleDias.Count > 0)
                {
                    query = query.Where(c => c.CumpleDia.HasValue && searchParam.CumpleDias.Contains(c.CumpleDia.Value));
                }

                if (searchParam.CumpleMeses.Count() > 0)
                {
                    query = query.Where(c => c.CumpleMes.HasValue && searchParam.CumpleMeses.Contains(c.CumpleMes.Value));
                }

                if (searchParam.CumpleAnios.Count() > 0)
                {
                    query = query.Where(c => c.CumpleAnio.HasValue && searchParam.CumpleAnios.Contains(c.CumpleAnio.Value));
                }

                if (searchParam.FechaCumpleDesde.HasValue)
                {
                    query = query.Where(c => c.CumpleAnio.HasValue && c.CumpleAnio >= searchParam.FechaCumpleDesde.Value.Year);
                    query = query.Where(c => c.CumpleMes.HasValue && c.CumpleMes >= searchParam.FechaCumpleDesde.Value.Month);
                    query = query.Where(c => c.CumpleDia.HasValue && c.CumpleDia >= searchParam.FechaCumpleDesde.Value.Day);
                }

                if (searchParam.FechaCumpleHasta.HasValue)
                {
                    query = query.Where(c => c.CumpleAnio.HasValue && c.CumpleAnio <= searchParam.FechaCumpleHasta.Value.Year);
                    query = query.Where(c => c.CumpleMes.HasValue && c.CumpleMes <= searchParam.FechaCumpleHasta.Value.Month);
                    query = query.Where(c => c.CumpleDia.HasValue && c.CumpleDia <= searchParam.FechaCumpleHasta.Value.Day);
                }

                if (searchParam.NacionalidadId.HasValue)
                {
                    query = query.Where(c => c.NacionalidadId == searchParam.NacionalidadId.Value);
                }

                if (searchParam.Provincias.Count > 0)
                {
                    query = query.Where(c => c.ProvinciaId.HasValue && searchParam.Provincias.Contains(c.ProvinciaId.Value));
                }

                if (searchParam.TipoRegistroBitacora.Count > 0)
                {
                    query = query.Where(c => c.ContactoBitacoras.Where(tr => searchParam.TipoRegistroBitacora.Contains(tr.TipoDeRegistro)).Count() > 0);
                }

                if (searchParam.EstadosEmail.Count > 0)
                {
                    query = query.Where(c => c.EstadoEmail.HasValue && searchParam.EstadosEmail.Contains(c.EstadoEmail.Value));
                }

                if (searchParam.Estados.Count() > 0)
                {
                    query = query.Where(c => c.Estado.HasValue && searchParam.Estados.Contains(c.Estado.Value));
                }

                if (searchParam.ListasDeDistribucion.Count() > 0)
                {
                    query = query.Where(c => c.ListaDistribucions.Where(l => searchParam.ListasDeDistribucion.Contains(l.Id)).Count() > 0);
                }

                if (searchParam.Dni.HasValue)
                {
                    query = query.Where(c => c.NroDocumento == searchParam.Dni);
                }

                if (!String.IsNullOrEmpty(searchParam.Email))
                {
                    // Soporto emails separados por coma
                    List<string> comaEmailsSinTrim = searchParam.Email.Split(',').ToList();
                    List<string> comaEmailsConTrim = comaEmailsSinTrim.Select(e => e.Trim()).ToList();

                    var predicate = PredicateBuilder.False<DbContacto>();

                    foreach (string emailSearch in comaEmailsConTrim)
                    {
                        string temp = emailSearch;
                        predicate = predicate.Or(p => p.Email.Contains(temp));
                    }

                    query = query.AsExpandable().Where(predicate);
                }

                if (searchParam.Sexo.HasValue)
                {
                    query = query.Where(c => c.Sexo == (searchParam.Sexo.Value == (int)SexoEnum.Masculino));
                }

                if (!String.IsNullOrEmpty(searchParam.Nombre))
                {
                    string searchNombre = ListsCrm.PrepareForSearch(searchParam.Nombre);
                    query = query.Where(c => c.NombreSearch.Contains(searchNombre));
                }

                if (!String.IsNullOrEmpty(searchParam.Apellido))
                {
                    string searchApellido = ListsCrm.PrepareForSearch(searchParam.Apellido);
                    query = query.Where(c => c.ApellidoSearch.Contains(searchApellido));
                }

                if (!String.IsNullOrEmpty(searchParam.Telefono))
                {
                    query = query.Where(c => c.ApellidoSearch.Contains(searchParam.Telefono));
                }

                if (!String.IsNullOrEmpty(searchParam.NroCredencial))
                {
                    query = query.Where(c => c.ApellidoSearch.Contains(searchParam.NroCredencial));
                }

                if (searchParam.Categorias.Count > 0)
                {
                    query = query.Where(c => c.Categorias.Where(ct => searchParam.Categorias.Contains(ct.Id)).Count() > 0);
                }

                if (searchParam.FechaCompraDesde.HasValue)
                {
                    DateTime fechaDesde = searchParam.FechaCompraDesde.Value.Date;
                    query = query.Where(c => c.Ventas.Where(cv => cv.DATE_OF_SALE >= fechaDesde).Count() > 0);
                }

                if (searchParam.FechaCompraHasta.HasValue)
                {
                    DateTime fechaHasta = searchParam.FechaCompraHasta.Value.Date.AddDays(1).AddSeconds(-1);
                    query = query.Where(c => c.Ventas.Where(cv => cv.DATE_OF_SALE <= fechaHasta).Count() > 0);
                }

                if (searchParam.FechaCreadoDesde.HasValue)
                {
                    DateTime creadoDesde = searchParam.FechaCreadoDesde.Value.Date;
                    query = query.Where(c => c.AuditFechaCreacion >= creadoDesde);
                }

                if (searchParam.FechaCreadoHasta.HasValue)
                {
                    DateTime creadoHasta = searchParam.FechaCreadoHasta.Value.AddDays(1).AddSeconds(-1);
                    query = query.Where(c => c.AuditFechaCreacion <= creadoHasta);
                }
            }

            totalDeResultados = query.Count();

            if (!String.IsNullOrEmpty(searchParam.SortingField))
            {
                if (searchParam.SortingField == "FechaUltimaCompra")
                {
                    if (searchParam.SortIsAsc)
                    {
                        query = query.OrderBy(c => c.ContactoVenta.FechaUltimaCompra);
                    }
                    else
                    {
                        query = query.OrderByDescending(c => c.ContactoVenta.FechaUltimaCompra);
                    }
                }
                else
                {
                    query = query.OrderByWithParam(searchParam.SortingField, searchParam.SortIsAsc).AsQueryable();
                }
            }

            if (searchParam.PageSize != 0)
            {
                query = query.Skip(searchParam.PageSkip).Take(searchParam.PageSize);
            }

            return query;
        }


        public static void LoadCustomerVeryBasicInfo(DbContacto dbContacto, Cliente registro)
        {
            registro.Id = dbContacto.Id;
            registro.TipoDocumentoId = dbContacto.TipoDocumentoId;
            registro.EmpresaId = dbContacto.EmpresaId;

            if (dbContacto.TipoDocumentoId.HasValue)
            {
                registro.TipoDocumento = dbContacto.TipoDocumento.Nombre;
            }

            registro.Dni = dbContacto.NroDocumento;
            registro.Email = dbContacto.Email;
            registro.Nombre = dbContacto.Nombre;
            registro.Apellido = dbContacto.Apellido;
            registro.NacionalidadId = dbContacto.NacionalidadId;
            registro.ProvinciaId = dbContacto.ProvinciaId;
            registro.Domicilio = dbContacto.Domicilio;
            if (dbContacto.Sexo.HasValue)
            {
                registro.Sexo = dbContacto.Sexo.Value ? 1 : 0;
            }

            registro.CodigoPostal = dbContacto.CodigoPostal;
            registro.CumpleDia = dbContacto.CumpleDia;
            registro.CumpleMes = dbContacto.CumpleMes;
            registro.CumpleAnio = dbContacto.CumpleAnio;
            registro.Estado = dbContacto.Estado;
            registro.EstadoEmail = dbContacto.EstadoEmail;
            registro.Telefono = dbContacto.Telefono;
            registro.NroCredencial = dbContacto.NroCredencial;
            registro.OrigenPuntoDeVentaId = dbContacto.OrigenPuntoDeVentaId;
            registro.OrigenId = dbContacto.OrigenId;
            registro.DeseaRecibirEmails = dbContacto.DeseaRecibirEmails;
            registro.CantidadHijos = dbContacto.CantidadHijos;
            registro.EdadHijoMenor = dbContacto.EdadHijoMenor;

            registro.AuditFechaCreacion = dbContacto.AuditFechaCreacion;
            registro.AuditUserNameCreacion = dbContacto.AuditUserNameCreacion;
        }

        public static void LoadCustomerBasicInfo(CrmContactoEntities ctxCrm, DbContacto dbContacto, Cliente registro)
        {
            LoadCustomerVeryBasicInfo(dbContacto, registro);

            var totalesParaContacto = ctxCrm.GetTotalesParaContacto(dbContacto.Id);
            var total = totalesParaContacto.SingleOrDefault();
            if (total != null)
            {
                registro.FechaUltimaCompra = total.FechaUltimaCompra;//dbContacto.ContactoVentas.Select(v => (DateTime?)v.FechaVenta).Max();
            }

            registro.Categorias.AddRange(dbContacto.Categorias.Select(c => new MaestroBase() { Id = c.Id, Nombre = c.Nombre }).ToList());
        }

        private void LoadCustomerBitacoraInfo(CrmContactoEntities ctxCrm, DbContacto dbContacto, Cliente cliente, bool? desdePdv)
        {
            IQueryable<DbContactoBitacora> query = dbContacto.ContactoBitacoras.AsQueryable();

            if (desdePdv.HasValue)
            {
                query = query.Where(c => c.TipoMensajeBitacoraId.HasValue && c.TipoMensajeBitacora.EsPdv == desdePdv.Value);
            }

            foreach (DbContactoBitacora dbContactoBitacora in query)
            {

                ClienteBitacora clienteBitacora = new ClienteBitacora();
                clienteBitacora.Id = dbContactoBitacora.Id;
                clienteBitacora.FechaCreacion = dbContactoBitacora.AuditFechaCreacion;
                clienteBitacora.TipoRegistroBitacora = dbContactoBitacora.TipoDeRegistro;
                clienteBitacora.TipoMensajeBitacoraId = dbContactoBitacora.TipoMensajeBitacoraId;
                clienteBitacora.Accion = dbContactoBitacora.Accion;
                clienteBitacora.AuditUserNameCreacion = dbContactoBitacora.AuditUserNameCreacion;
                if (dbContactoBitacora.PuntoDeVentaId.HasValue)
                {
                    clienteBitacora.PuntoDeVentaId = dbContactoBitacora.PuntoDeVentaId;
                    clienteBitacora.PuntoDeVentaNombre = dbContactoBitacora.PuntoDeVenta.Nombre;
                }

                cliente.Bitacora.Add(clienteBitacora);
            }
        }

        private void LoadCustomerListaDistribucion(CrmContactoEntities ctxCrm, DbContacto dbContacto, Cliente cliente)
        {
            foreach (var dbLista in dbContacto.ListaDistribucions)
            {
                ListaDeDistribucion lista = new ListaDeDistribucion();
                LoadListaDistribucionFromDb(lista, dbLista);
                cliente.ListasDeDistribucion.Add(lista);
            }
        }

        private static void SetCustomerBasicInfo(Cliente customer, DbContacto dbContacto, bool actualizando = false)
        {
            if (!actualizando || (actualizando && customer.TipoDocumentoId.HasValue))
                dbContacto.TipoDocumentoId = customer.TipoDocumentoId;

            if (!actualizando || (actualizando && customer.Dni.HasValue))
                dbContacto.NroDocumento = customer.Dni;

            if (!actualizando || (actualizando && customer.EstadoEmail.HasValue))
                dbContacto.EstadoEmail = customer.EstadoEmail;

            if (!String.IsNullOrEmpty(customer.Email))
            {
                if (dbContacto.Email != customer.Email.ToLower())
                {
                    dbContacto.EstadoEmail = (int)EstadoEmail.Alta;
                }

                dbContacto.Email = customer.Email.ToLower();
            }

            if (!String.IsNullOrEmpty(customer.Nombre))
            {
                dbContacto.Nombre = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(customer.Nombre.ToLower());
                dbContacto.NombreSearch = ListsCrm.PrepareForSearch(customer.Nombre);
            }

            if (!String.IsNullOrEmpty(customer.Apellido))
            {
                dbContacto.Apellido = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(customer.Apellido.ToLower());
                dbContacto.ApellidoSearch = ListsCrm.PrepareForSearch(customer.Apellido);
            }

            if (!actualizando || (actualizando && customer.NacionalidadId.HasValue))
                dbContacto.NacionalidadId = customer.NacionalidadId;

            if (!actualizando || (actualizando && customer.ProvinciaId.HasValue))
                dbContacto.ProvinciaId = customer.ProvinciaId;

            if (!actualizando || (actualizando && !String.IsNullOrEmpty(customer.Domicilio)))
                dbContacto.Domicilio = customer.Domicilio;

            if (!actualizando || (actualizando && !String.IsNullOrEmpty(customer.CodigoPostal)))
                dbContacto.CodigoPostal = customer.CodigoPostal;

            if (!actualizando || (actualizando && customer.CumpleDia.HasValue))
                dbContacto.CumpleDia = customer.CumpleDia;

            if (!actualizando || (actualizando && customer.CumpleMes.HasValue))
                dbContacto.CumpleMes = customer.CumpleMes;

            if (!actualizando || (actualizando && customer.CumpleAnio.HasValue))
                dbContacto.CumpleAnio = customer.CumpleAnio;

            if (!actualizando || (actualizando && customer.Estado.HasValue))
                dbContacto.Estado = customer.Estado;

            if (!actualizando || (actualizando && !String.IsNullOrEmpty(customer.Telefono)))
                dbContacto.Telefono = customer.Telefono;

            if (!actualizando || (actualizando && !String.IsNullOrEmpty(customer.NroCredencial)))
                dbContacto.NroCredencial = customer.NroCredencial;

            if (!actualizando || (actualizando && customer.DeseaRecibirEmails != dbContacto.DeseaRecibirEmails))
                dbContacto.DeseaRecibirEmails = customer.DeseaRecibirEmails;

            if ((!actualizando && customer.Sexo.HasValue) || (actualizando && customer.Sexo.HasValue))
            {
                dbContacto.Sexo = customer.Sexo.Value == (int)SexoEnum.Masculino;
            }

            if (!actualizando || (actualizando && customer.CantidadHijos != dbContacto.CantidadHijos))
            {
                dbContacto.CantidadHijos = customer.CantidadHijos;
            }

            if (!actualizando || (actualizando && customer.CantidadHijos != dbContacto.CantidadHijos))
            {
                dbContacto.EdadHijoMenor = customer.EdadHijoMenor;
            }
        }

        public Cliente GetCustomerById(ServiceOptions options, int customerId, ClienteByIdOptions clientOptions)
        {
            Cliente cliente = new Cliente();
            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                DbContacto dbContacto = ctxCrm.DbContactoes.Where(c => c.Id == customerId).SingleOrDefault();
                if (dbContacto != null)
                {
                    cliente.Id = dbContacto.Id;
                    if (clientOptions.LoadBasicInfo)
                        LoadCustomerBasicInfo(ctxCrm, dbContacto, cliente);

                    if (clientOptions.LoadSales)
                        LoadCustomerSales(ctxCrm, dbContacto, cliente);

                    if (clientOptions.LoadBitacora)
                        LoadCustomerBitacoraInfo(ctxCrm, dbContacto, cliente, clientOptions.DesdePdv);

                    if (clientOptions.LoadListasDeDistribucion)
                        LoadCustomerListaDistribucion(ctxCrm, dbContacto, cliente);
                }
            }

            return cliente;
        }

        public Cliente SaveCustomer(ServiceOptions options, Cliente customer)
        {
            DateTime now = DateTime.Now;

            bool sendEmail = false;
            bool esNuevo = customer.Id == 0;

            List<ICustomerServiceHook> hookList = ServiceFactoryInternal.Instance.GetCustomerServiceHooks(customer.EmpresaId);
            foreach (ICustomerServiceHook hookBefore in hookList)
            {
                hookBefore.BeforeSave(customer);
            }

            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbContacto dbContacto = SaveCustomerInternal(options, customer, ctx);

                    ctx.SaveChanges();

                    tScope.Complete();
                    customer.Id = dbContacto.Id;
                    sendEmail = esNuevo && customer.DeseaRecibirEmails;
                }
            }

            if (sendEmail)
            {
                ContactoForEmail contactoForEmail = new ContactoForEmail();
                contactoForEmail.ContactoId = customer.Id;
                contactoForEmail.Email = customer.Email;
                contactoForEmail.EmpresaId = customer.EmpresaId;
                contactoForEmail.UserName = options.UserName;
                contactoForEmail.Origen = (int)TipoContactoOrigen.Backoffice;
                CommonCrmTaskManager.SendEmailToCustomerInThread(contactoForEmail);
            }

            // Ejecuto las extensiones en Thread
            CommonCrmTaskManager.PerformHooksToCustomerInThread(new List<Cliente>() { customer }, hookList);

            return GetCustomerById(options, customer.Id, new ClienteByIdOptions() { LoadBasicInfo = true, LoadBitacora = true, LoadSales = true });
        }

        public List<ClienteWrap> SaveCustomerList(ServiceOptions options, List<ClienteWrap> customerList)
        {
            DateTime now = DateTime.Now;
            List<Cliente> clienteList = new List<Cliente>();
            foreach (ClienteWrap wrap in customerList)
            {
                if (!wrap.TieneErrores)
                {
                    List<ICustomerServiceHook> hookList = ServiceFactoryInternal.Instance.GetCustomerServiceHooks(wrap.EmpresaId);
                    foreach (ICustomerServiceHook hookBefore in hookList)
                    {
                        hookBefore.BeforeSave(wrap);
                    }

                    using (TransactionScope tScope = new TransactionScope())
                    {
                        using (CrmContactoEntities ctx = new CrmContactoEntities())
                        {
                            try
                            {
                                DbContacto dbContacto = SaveCustomerInternal(options, wrap, ctx, true);

                                ctx.SaveChanges();

                                tScope.Complete();

                                wrap.Id = dbContacto.Id;
                                wrap.FueIncorporado = true;
                                clienteList.Add(wrap as Cliente);
                            }
                            catch (Exception ex)
                            {
                                if (String.IsNullOrEmpty(wrap.Mensaje))
                                {
                                    wrap.Mensaje = string.Empty;
                                }

                                wrap.Mensaje += ex.Message;
                                wrap.FueIncorporado = false;
                            }
                        }
                    }

                    // Ejecuto las extensiones en Thread
                    CommonCrmTaskManager.PerformHooksToCustomerInThread(clienteList, hookList);
                }
            }

            return customerList;
        }

        private void ValidarContacto(Cliente customer, CrmContactoEntities ctx, bool actualizandoPorDNI = false, bool actualizandoPorEmail = false)
        {
            StringBuilder builder = new StringBuilder();
            // Validación del maximo de edad
            if (customer.CumpleAnio.HasValue)
            {
                Dictionary<string, string> config = ListsCrm.GetCompanyConfigurationKeyValues(customer.EmpresaId);
                if (config.ContainsKey(CommonConstants.ValidacionMaximoEdad))
                {
                    int maximoEdad = Convert.ToInt32(config[CommonConstants.ValidacionMaximoEdad]);
                    if ((DateTime.Now.Date.Year - customer.CumpleAnio.Value) < maximoEdad)
                    {
                        builder.Append(string.Format(LocalizationProvider.Instance["Validacion.EdadMaxima"], maximoEdad));
                    }
                }
            }

            // Validaciones

            // Tiene que tener email o documento (en brasil no es necesario y si el documento)
            if (String.IsNullOrEmpty(customer.Email) && !customer.Dni.HasValue)
            {
                builder.Append(LocalizationProvider.Instance["ExceptionClienteSinEmail"]); //throw new SvcBusinessException();
                builder.AppendLine();
            }

            // valido que no exista el contacto por email, menos cuando actualizo por DNI
            if (!actualizandoPorEmail)
            {
                if (ctx.DbContactoes.FilterLogicalRemoved().Where(c => c.Email == customer.Email && c.Id != customer.Id && c.EmpresaId == customer.EmpresaId).Count() > 0)
                {
                    builder.Append(LocalizationProvider.Instance["ExceptionYaExisteClienteConEseEmail"]);
                    builder.AppendLine();
                }
            }

            if (!actualizandoPorDNI)
            {
                if (ctx.DbContactoes.FilterLogicalRemoved().Where(c => c.NroDocumento == customer.Dni && c.Id != customer.Id && c.EmpresaId == customer.EmpresaId).Count() > 0)
                {
                    builder.Append(LocalizationProvider.Instance["ExceptionYaExisteClienteConEseDNI"]);
                    builder.AppendLine();
                }
            }

            RegexUtility reg = new RegexUtility();
            if (!reg.IsValidEmail(customer.Email))
            {
                builder.AppendFormat(LocalizationProvider.Instance["Bo.Excel.Contacto.EmailInvalido"], customer.Email);
                builder.AppendLine();
            }

            if (builder.Length > 0)
            {
                throw new SvcBusinessException(builder.ToString());
            }
        }

        private DbContacto SaveCustomerInternal(ServiceOptions options, Cliente customer, CrmContactoEntities ctx, bool actualizarSiTieneDocumentoOEmail = false)
        {
            DbContacto dbContacto;

            dbContacto = ctx.DbContactoes.Where(c => c.Id == customer.Id).SingleOrDefault();

            bool actualizandoPorEmail = false;
            bool actualizandoPorDNI = false;
            bool esNuevo = false;

            if (dbContacto == null && actualizarSiTieneDocumentoOEmail)
            {
                // Analizo si existe por dni o email
                var dbContactoConEmail = ctx.DbContactoes.FilterLogicalRemoved().Where(c => c.Email == customer.Email && c.Id != customer.Id && c.EmpresaId == customer.EmpresaId).SingleOrDefault();
                if (dbContactoConEmail != null)
                {
                    dbContacto = dbContactoConEmail;
                    actualizandoPorEmail = true;
                }
                else
                {
                    var dbContactoConDNI = ctx.DbContactoes.FilterLogicalRemoved().Where(c => c.NroDocumento == customer.Dni && c.Id != customer.Id && c.EmpresaId == customer.EmpresaId).SingleOrDefault();
                    if (dbContactoConDNI != null)
                    {
                        dbContacto = dbContactoConDNI;
                        actualizandoPorDNI = true;
                    }
                }
            }

            ValidarContacto(customer, ctx, actualizandoPorDNI, actualizandoPorEmail);


            if (dbContacto == null)
            {
                esNuevo = true;

                dbContacto = new DbContacto();
                ctx.DbContactoes.AddObject(dbContacto);
                dbContacto.AuditFechaCreacion = DateTime.Now;
                dbContacto.AuditUserNameCreacion = options.UserName;
                dbContacto.EmpresaId = customer.EmpresaId;

                if (customer.OrigenId == 0)
                {
                    dbContacto.OrigenId = (int)TipoContactoOrigen.Backoffice;
                }
                else
                {
                    dbContacto.OrigenId = customer.OrigenId;
                }
            }
            else // ya existe
            {
                dbContacto.AuditFechaModificacion = DateTime.Now;
                dbContacto.AuditUserNameModificacion = options.UserName;
            }

            customer.AuditUserNameCreacion = dbContacto.AuditUserNameCreacion;
            if (String.IsNullOrEmpty(customer.UserName))
            {
                customer.UserName = options.UserName;
            }

            if (esNuevo)
            {
                var dbBitacora = CrearBitacoraCreacion(string.Format(LocalizationProvider.Instance["Bitacora.Mensaje.ContactoCreadoEnBO"], options.UserName, DateTime.Now), options.UserName);
                dbContacto.ContactoBitacoras.Add(dbBitacora);
                customer.AuditFechaCreacion = DateTime.Now;
            }

            if (!String.IsNullOrEmpty(customer.Email))
            {
                if (dbContacto.Email != customer.Email.ToLower())
                {
                    dbContacto.EstadoEmail = (int)EstadoEmail.Alta;
                    // registro en la bitacora el nuevo email
                    var dbBitacora = CrearBitacoraEmail(string.Format(LocalizationProvider.Instance["Bitacora.Mensaje.CambioDeEmail"], customer.Email), options.UserName);
                    dbContacto.ContactoBitacoras.Add(dbBitacora);
                }
            }

            SetCustomerBasicInfo(customer, dbContacto, actualizandoPorDNI || actualizandoPorEmail);

            SetCustomerCategories(customer, ctx, dbContacto, actualizandoPorDNI || actualizandoPorEmail);

            return dbContacto;
        }

        private static DbContactoBitacora CrearBitacoraEmail(string mensaje, string userName)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Email;
            dbContactoBitacora.Accion = mensaje;
            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = DateTime.Now;
            return dbContactoBitacora;
        }

        private static DbContactoBitacora CrearBitacoraCreacion(string mensaje, string userName)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Creacion;
            dbContactoBitacora.Accion = mensaje;
            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = DateTime.Now;
            return dbContactoBitacora;
        }

        public static DbContactoBitacora CrearBitacoraCambioDeEstado(string mensaje, string userName)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Mensaje;
            dbContactoBitacora.Accion = mensaje;
            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = DateTime.Now;
            return dbContactoBitacora;
        }

        private static void SetCustomerCategories(Cliente customer, CrmContactoEntities ctx, DbContacto dbContacto, bool actualizando = false)
        {
            // TODO: analisis de de actualización de categorias
            if (!actualizando || (actualizando && dbContacto.Categorias.Count == 0))
            {
                List<int> categoriaIdList = customer.Categorias.Select(m => m.Id).ToList();

                List<DbCategoria> dbCategoriaList = ctx.DbCategorias.Where(c => categoriaIdList.Contains(c.Id)).ToList();
                dbContacto.Categorias.Clear();

                foreach (DbCategoria dbCategoria in dbCategoriaList)
                {
                    dbContacto.Categorias.Add(dbCategoria);
                }
            }
        }

        public ClienteBitacora SaveCustomerBitacora(ServiceOptions options, ClienteBitacora clienteBitacora)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
                    ctx.DbContactoBitacoras.AddObject(dbContactoBitacora);

                    dbContactoBitacora.ContactoId = clienteBitacora.Id;
                    dbContactoBitacora.Accion = clienteBitacora.Accion;
                    dbContactoBitacora.TipoDeRegistro = clienteBitacora.TipoRegistroBitacora;
                    dbContactoBitacora.TipoMensajeBitacoraId = clienteBitacora.TipoMensajeBitacoraId;
                    dbContactoBitacora.PuntoDeVentaId = clienteBitacora.PuntoDeVentaId;
                    dbContactoBitacora.ContactoId = clienteBitacora.ContactoId;
                    dbContactoBitacora.AuditFechaCreacion = DateTime.Now;
                    dbContactoBitacora.AuditUserNameCreacion = options.UserName;
                    ctx.SaveChanges();
                    tScope.Complete();

                    clienteBitacora.Id = dbContactoBitacora.Id;
                }
            }

            return clienteBitacora;
        }


        private void LoadCustomerSales(CrmContactoEntities ctxCrm, DbContacto dbContacto, Cliente cliente)
        {
            //var ventasDelContacto = ctxCrm.AR_GetVentasParaContacto(cliente.Id);
            //foreach (var ventaDelContacto in ventasDelContacto)
            //{
            //    ClienteVenta venta = new ClienteVenta();
            //    venta.Id = ventaDelContacto.Id;
            //    venta.NroTransaccion = ventaDelContacto.nrotrans;
            //    venta.FechaVenta = ventaDelContacto.fecharegistracion;
            //    venta.Talonario = ventaDelContacto.talonario;
            //    venta.Prefijo = ventaDelContacto.prefijo;
            //    venta.NumeroFactura = ventaDelContacto.nroregistracion.ToString();
            //    venta.Monto = ventaDelContacto.importetotal;
            //    venta.Cantidad = ventaDelContacto.cantidad;
            //    venta.CodigoProducto = string.Format("{0}{1}{2}", ventaDelContacto.coditem, ventaDelContacto.codcolor, ventaDelContacto.codtalle); // TODO: completar el coditem + codcolor + codtalle
            //    venta.Descripcion = ventaDelContacto.descripcion;
            //    venta.PuntoVentaId = ventaDelContacto.puntoDeVentaId;
            //    venta.PuntoVentaName = ventaDelContacto.puntoVentaNombre;
            //    cliente.Ventas.Add(venta);
            //}

            List<DbContactoVentaPorPdv> dbContactoVentasPdvList = dbContacto.ContactoVentas.ToList();

            // Filtro las que tienen cupon
            dbContactoVentasPdvList = dbContactoVentasPdvList.Where(cv => cv.CuponId.HasValue).ToList();

            var ventasDelContacto = ctxCrm.GetVentasParaContactoV2(dbContacto.Id);
            foreach (var ventaDelContacto in ventasDelContacto)
            {
                ClienteVenta venta = new ClienteVenta();
                //venta.Id = ventaDelContacto.POINT_OF_SALES_ID;
                venta.NroTransaccion = ventaDelContacto.TRANSACTION_CODE;
                venta.FechaVenta = ventaDelContacto.DATE_OF_SALE.Value;
                venta.Talonario = ventaDelContacto.TALONARIO;
                venta.Prefijo = ventaDelContacto.PREFIJO;
                venta.NumeroFactura = ventaDelContacto.INVOICE_NUMBER.ToString();
                venta.Monto = ventaDelContacto.ITEM_AMOUNT;
                venta.Cantidad = ventaDelContacto.ITEM_QUANTITY;
                venta.CodigoProducto = string.Format("{0}{1}{2}", ventaDelContacto.ITEM_CODE, ventaDelContacto.ITEM_COLOR, ventaDelContacto.ITEM_SIZE);
                venta.Descripcion = ventaDelContacto.ITEM_DESCRIPTION;
                //venta.PuntoVentaId = ventaDelContacto.POINT_OF_SALES_ID;
                venta.PuntoVentaName = ventaDelContacto.POINT_OF_SALES_NAME;
                venta.PuntoVentaCodigo = ventaDelContacto.POINT_OF_SALES_CODE;
                venta.SalesMan = ventaDelContacto.SALESMAN;
                cliente.Ventas.Add(venta);

                // Si tiene cupon lo agrego
                var dbContactoVentaPosible = dbContactoVentasPdvList.Where(cv => cv.FechaVenta.Date == venta.FechaVenta.Date && cv.NroFactura == ventaDelContacto.INVOICE_NUMBER && cv.PuntoDeVenta.CodigoExterno == ventaDelContacto.POINT_OF_SALES_CODE).FirstOrDefault();
                if (dbContactoVentaPosible != null)
                {
                    venta.Cupon = dbContactoVentaPosible.AccionDeMarketingCupone.CodigoCupon;
                }
            }
        }

        public ClienteCantidades GetCantidadDeContactos(int empresaId, DateTime mesEnCurso)
        {
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                var results = ctx.All_GetContactosCountBaseYMes(empresaId, mesEnCurso);

                var result = results.First();
                return new ClienteCantidades()
                {
                    CantidadContactosMesEnCurso = result.TotalContactosMesEnCurso.Value,
                    CantidadDeContactosTotales = result.TotalContactos.Value
                };
            }
        }

        public List<PlanDeMarketing> GetPlanesDeMarketing(ServiceOptions options, PlanDeMarketingSearch search)
        {
            List<PlanDeMarketing> planDeMarketingList = new List<PlanDeMarketing>();
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    IQueryable<DbPlanDeMarketing> query = ctx.DbPlanDeMarketings.FilterLogicalRemoved().Where(e => e.EmpresaId == search.EmpresaId);

                    if (search.Id.HasValue)
                    {
                        query = query.Where(c => c.Id == search.Id.Value);
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(search.NombreLike))
                        {
                            query = query.Where(c => c.Nombre.Contains(search.NombreLike));
                        }

                        if (!String.IsNullOrEmpty(search.DescripcionLike))
                        {
                            query = query.Where(c => c.Descripcion.Contains(search.DescripcionLike));
                        }

                        if (search.Estado.HasValue)
                        {
                            query = query.Where(c => c.Estado == search.Estado.Value);
                        }

                        if (search.VigenciaDesde.HasValue)
                        {
                            query = query.Where(c => c.VigenciaDesde >= search.VigenciaDesde.Value);
                        }

                        if (search.VigenciaHasta.HasValue)
                        {
                            query = query.Where(c => c.VigenciaHasta <= search.VigenciaHasta);
                        }
                    }

                    List<DbPlanDeMarketing> dbPlanDeMarketingList = query.ToList();
                    foreach (DbPlanDeMarketing dbPlanDeMarketing in dbPlanDeMarketingList)
                    {
                        PlanDeMarketing planDeMarketing = new PlanDeMarketing();
                        LoadPlanDeMarketingFromDbBasicInfo(planDeMarketing, dbPlanDeMarketing);

                        if (!planDeMarketing.Estado.HasValue)
                        {
                            planDeMarketing.Estado = (int)EstadoPlanDeMarketing.NoIniciado;
                        }


                        if (search.LoadAccionesDeMarketing)
                        {
                            LoadAccionesDeMarketingParaPlan(ctx, planDeMarketing, dbPlanDeMarketing);
                        }

                        // analizo el estado del plan de marketing
                        AnalizarEstadoPlanDeMarketing(planDeMarketing);

                        if (planDeMarketing.Estado != dbPlanDeMarketing.Estado && planDeMarketing.Estado.HasValue)
                        {
                            dbPlanDeMarketing.Estado = planDeMarketing.Estado.Value;
                            ctx.SaveChanges();
                        }

                        planDeMarketingList.Add(planDeMarketing);
                    }

                    tScope.Complete();
                }
            }

            return planDeMarketingList;
        }

        private static void AnalizarEstadoPlanDeMarketing(PlanDeMarketing planDeMarketing)
        {
            EstadoPlanDeMarketing estadoPlanActual = (EstadoPlanDeMarketing)planDeMarketing.Estado;
            bool unoComenzado = false;
            bool todosFinalizados = true;

            if (estadoPlanActual != EstadoPlanDeMarketing.Cancelado || estadoPlanActual != EstadoPlanDeMarketing.Finalizado)
            {
                foreach (var accion in planDeMarketing.AccionDeMarketingList)
                {
                    if (estadoPlanActual != EstadoPlanDeMarketing.Cancelado)
                    {
                        if (accion.Estado == (int)EstadoPlanDeMarketing.EnCurso)
                        {
                            unoComenzado = true;
                        }

                        if (accion.Estado != (int)EstadoPlanDeMarketing.Finalizado || accion.Estado != (int)EstadoPlanDeMarketing.Cancelado)
                        {
                            todosFinalizados = false;
                        }
                    }
                }

                if (unoComenzado)
                {
                    estadoPlanActual = EstadoPlanDeMarketing.EnCurso;
                }
                else
                {
                    if (todosFinalizados && !planDeMarketing.VigenciaDesde.HasValue)
                    {
                        estadoPlanActual = EstadoPlanDeMarketing.Finalizado;
                    }
                    else
                    {
                        if (planDeMarketing.VigenciaDesde.HasValue && planDeMarketing.VigenciaDesde.Value >= DateTime.Now)
                        {
                            estadoPlanActual = EstadoPlanDeMarketing.EnCurso;
                        }
                    }
                }

                if (planDeMarketing.VigenciaHasta.HasValue && planDeMarketing.VigenciaHasta.Value <= DateTime.Now)
                {
                    estadoPlanActual = EstadoPlanDeMarketing.Finalizado;
                }

                planDeMarketing.Estado = (int)estadoPlanActual;
            }
        }

        private void LoadAccionesDeMarketingParaPlan(CrmContactoEntities ctx, PlanDeMarketing planDeMarketing, DbPlanDeMarketing dbPlanDeMarketing)
        {
            foreach (var dbAccionDeMarketing in dbPlanDeMarketing.AccionDeMarketings)
            {
                AccionDeMarketing accionDeMarketing = new AccionDeMarketing();
                if (!dbAccionDeMarketing.Estado.HasValue)
                {
                    dbAccionDeMarketing.Estado = (int)EstadoPlanDeMarketing.NoIniciado;
                    ctx.SaveChanges();
                }

                EstadoPlanDeMarketing estadoPrevioAccion = (EstadoPlanDeMarketing)dbAccionDeMarketing.Estado;

                LoadAccionDeMarketingBasicInfo(accionDeMarketing, dbAccionDeMarketing);

                if ((EstadoPlanDeMarketing)accionDeMarketing.Estado != estadoPrevioAccion)
                {
                    dbAccionDeMarketing.Estado = accionDeMarketing.Estado;
                    ctx.SaveChanges();
                }

                planDeMarketing.AccionDeMarketingList.Add(accionDeMarketing);
            }
        }

        private void LoadAccionDeMarketingBasicInfo(AccionDeMarketing accionDeMarketing, DbAccionDeMarketing dbAccionDeMarketing)
        {
            EntityMapper.Map(dbAccionDeMarketing, accionDeMarketing);
            accionDeMarketing.PlanDeMarketingNombre = dbAccionDeMarketing.PlanDeMarketing.Nombre;

            AnalizarEstadoAccionDeMarketing(accionDeMarketing);

            //accionDeMarketing.Id = dbAccionDeMarketing.Id;
            //accionDeMarketing.PlanDeMarketingId = dbAccionDeMarketing.PlanDeMarketingId;
            ////accionDeMarketing.PlanDeMarketingNombre = dbAccionDeMarketing.PlanDeMarketing.Nombre;
            //accionDeMarketing.Nombre = dbAccionDeMarketing.Nombre;
            //accionDeMarketing.Descripcion = dbAccionDeMarketing.Descripcion;
            //accionDeMarketing.CodigoParaPDV = dbAccionDeMarketing.CodigoParaPDV;
            //accionDeMarketing.FechaDesde = dbAccionDeMarketing.FechaDesde;
            //accionDeMarketing.FechaHasta = dbAccionDeMarketing.FechaHasta;
            //accionDeMarketing.Discriminador = dbAccionDeMarketing.Discriminador;
            //accionDeMarketing.ROIDinero = dbAccionDeMarketing.ROIDinero;
            //accionDeMarketing.ROIPorcentaje = dbAccionDeMarketing.ROIPorcentaje;
            //accionDeMarketing.Inversion = dbAccionDeMarketing.Inversion;
            //accionDeMarketing.EficaciaEsperada = dbAccionDeMarketing.EficaciaEsperada;
        }

        private static void AnalizarEstadoAccionDeMarketing(AccionDeMarketing accionDeMarketing)
        {
            // Analizo el estado
            EstadoPlanDeMarketing estadoActual = (EstadoPlanDeMarketing)accionDeMarketing.Estado;
            DateTime now = DateTime.Now;
            if (accionDeMarketing.FechaDesde.HasValue)
            {
                if (estadoActual != EstadoPlanDeMarketing.Cancelado || estadoActual != EstadoPlanDeMarketing.Finalizado)
                {
                    if (accionDeMarketing.FechaDesde.Value <= now)
                    {
                        estadoActual = EstadoPlanDeMarketing.EnCurso;
                    }
                }
            }

            if (accionDeMarketing.FechaHasta.HasValue)
            {
                if (estadoActual != EstadoPlanDeMarketing.Cancelado || estadoActual != EstadoPlanDeMarketing.Finalizado)
                {
                    if (accionDeMarketing.FechaHasta.Value < now)
                    {
                        estadoActual = EstadoPlanDeMarketing.Finalizado;
                    }
                }
            }

            accionDeMarketing.Estado = (int)estadoActual;
        }

        private void LoadPlanDeMarketingFromDbBasicInfo(PlanDeMarketing planDeMarketing, DbPlanDeMarketing dbPlanDeMarketing)
        {
            EntityMapper.Map(dbPlanDeMarketing, planDeMarketing);
            //planDeMarketing.Id = dbPlanDeMarketing.Id;
            //planDeMarketing.Nombre = dbPlanDeMarketing.Nombre;
            //planDeMarketing.Descripcion = dbPlanDeMarketing.Descripcion;
            //planDeMarketing.VigenciaDesde = dbPlanDeMarketing.VigenciaDesde;
            //planDeMarketing.VigenciaHasta = dbPlanDeMarketing.VigenciaHasta;
            //planDeMarketing.Estado = dbPlanDeMarketing.Estado;
            //planDeMarketing.EmpresaId = dbPlanDeMarketing.EmpresaId;
        }

        private void LoadListaDistribucionFromDb(ListaDeDistribucion listaDistribucion, DbListaDistribucion dbListaDistribucion)
        {
            listaDistribucion.Id = dbListaDistribucion.Id;
            listaDistribucion.Nombre = dbListaDistribucion.Nombre;
            listaDistribucion.Descripcion = dbListaDistribucion.Descripcion;
            listaDistribucion.Estado = dbListaDistribucion.Estado;
        }

        public PlanDeMarketing SavePlanDeMarketing(ServiceOptions options, PlanDeMarketing planDeMarketing)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbPlanDeMarketing dbPlanDeMarketing = ctx.DbPlanDeMarketings.FilterLogicalRemoved().Where(c => c.Id == planDeMarketing.Id).SingleOrDefault();
                    if (dbPlanDeMarketing == null)
                    {
                        dbPlanDeMarketing = new DbPlanDeMarketing();
                        ctx.DbPlanDeMarketings.AddObject(dbPlanDeMarketing);
                        dbPlanDeMarketing.EmpresaId = planDeMarketing.EmpresaId;
                        dbPlanDeMarketing.AuditFechaCreacion = DateTime.Now;
                        dbPlanDeMarketing.AuditUserNameCreacion = options.UserName;
                    }
                    else
                    {
                        dbPlanDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbPlanDeMarketing.AuditUserNameModificacion = options.UserName;
                    }

                    dbPlanDeMarketing.Nombre = planDeMarketing.Nombre;
                    dbPlanDeMarketing.Descripcion = planDeMarketing.Descripcion;
                    dbPlanDeMarketing.Responsable = planDeMarketing.Responsable;
                    dbPlanDeMarketing.Estado = planDeMarketing.Estado.Value;
                    dbPlanDeMarketing.VigenciaDesde = planDeMarketing.VigenciaDesde;
                    dbPlanDeMarketing.VigenciaHasta = planDeMarketing.VigenciaHasta;

                    ctx.SaveChanges();
                    tScope.Complete();
                    planDeMarketing.Id = dbPlanDeMarketing.Id;
                }
            }

            return planDeMarketing;
        }

        public void AddListaDistribucionesAAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, List<int> listaDistribucionIds)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;

                        List<DbListaDistribucion> dbListasDeDistribucionList = ctx.DbListaDistribucions.FilterLogicalRemoved().Where(l => listaDistribucionIds.Contains(l.Id)).ToList();
                        foreach (var dbListaDistribucion in dbListasDeDistribucionList)
                        {
                            if (dbAccionDeMarketing.ListaDistribucions.Where(l => l.Id == dbListaDistribucion.Id).Count() == 0)
                            {
                                dbAccionDeMarketing.ListaDistribucions.Add(dbListaDistribucion);
                            }
                        }

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public List<AccionDeMarketingComunicacionTipo> GetMarketingComunicacionTipo(TipoAccionDeMarketingComunicacionSearch search)
        {
            List<AccionDeMarketingComunicacionTipo> tiposList = new List<AccionDeMarketingComunicacionTipo>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbAccionDeMarketingComunicacionTipo> query = ctx.DbAccionDeMarketingComunicacionTipoes.FilterLogicalRemoved();

                query = query.Where(e => e.EmpresaId == search.EmpresaId);

                if (search.Id.HasValue)
                {
                    query = query.Where(p => p.Id == search.Id.Value);
                }
                else if (search.AccionDeMarketingId.HasValue)
                {
                    query = query.Where(p => p.AccionDeMarketingComunicacions.Where(a => a.Id == search.AccionDeMarketingId.Value).Count() == 1);
                }
                else
                {
                    if (!String.IsNullOrEmpty(search.NombreLike))
                    {
                        query = query.Where(p => p.Nombre == search.NombreLike);
                    }
                }

                foreach (var dbAccionMktComunicacionTipo in query)
                {
                    AccionDeMarketingComunicacionTipo tipo = new AccionDeMarketingComunicacionTipo();
                    EntityMapper.Map(dbAccionMktComunicacionTipo, tipo);

                    var dbConfig = dbAccionMktComunicacionTipo.AccionDeMarketingComunicacionConfiguracion;
                    EntityMapper.Map(dbConfig, tipo.Configuracion);

                    tiposList.Add(tipo);
                }
            }

            return tiposList;
        }

        public AccionDeMarketingComunicacionTipo SaveMarketingComunicacionTipo(ServiceOptions options, AccionDeMarketingComunicacionTipo tipo)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbTipo = ctx.DbAccionDeMarketingComunicacionTipoes.Where(t => t.Id == tipo.Id).SingleOrDefault();
                    if (dbTipo == null)
                    {
                        dbTipo = new DbAccionDeMarketingComunicacionTipo();
                        ctx.DbAccionDeMarketingComunicacionTipoes.AddObject(dbTipo);
                        dbTipo.AuditFechaCreacion = now;
                        dbTipo.AuditUserNameCreacion = options.UserName;
                    }

                    EntityMapper.Map(tipo, dbTipo, "Id");

                    dbTipo.AuditFechaModificacion = now;
                    dbTipo.AuditUserNameModificacion = options.UserName;

                    ctx.SaveChanges();
                    tScope.Complete();
                    tipo.Id = dbTipo.Id;
                }
            }

            return tipo;
        }

        public void EliminarMarketingComunicacionTipo(ServiceOptions options, int tipoId)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbTipo = ctx.DbAccionDeMarketingComunicacionTipoes.Where(t => t.Id == tipoId).SingleOrDefault();
                    if (dbTipo != null)
                    {
                        dbTipo.AuditFechaModificacion = now;
                        dbTipo.AuditUserNameModificacion = options.UserName;
                        dbTipo.Removed = true;
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public void AddListaDistribucionesAConctacto(ServiceOptions options, int contactoId, List<int> listaDistribucionIds)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbContacto dbContacto = ctx.DbContactoes.FilterLogicalRemoved().Where(c => c.Id == contactoId).SingleOrDefault();
                    if (dbContacto != null)
                    {
                        dbContacto.AuditFechaModificacion = DateTime.Now;
                        dbContacto.AuditUserNameModificacion = options.UserName;

                        List<DbListaDistribucion> dbListasDeDistribucionList = ctx.DbListaDistribucions.FilterLogicalRemoved().Where(l => listaDistribucionIds.Contains(l.Id)).ToList();
                        foreach (var dbListaDistribucion in dbListasDeDistribucionList)
                        {
                            if (dbContacto.ListaDistribucions.Where(l => l.Id == dbListaDistribucion.Id).Count() == 0)
                            {
                                dbContacto.ListaDistribucions.Add(dbListaDistribucion);
                            }
                        }

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public void EliminarListaDistribucionDeAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, int listaDistribucionId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        var lista = dbAccionDeMarketing.ListaDistribucions.Where(l => l.Id == listaDistribucionId).SingleOrDefault();
                        if (lista != null)
                        {
                            dbAccionDeMarketing.ListaDistribucions.Remove(lista);
                            ctx.SaveChanges();
                            tScope.Complete();
                        }
                    }
                }
            }
        }

        public void EliminarResultadoDeAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, int resultadoId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketingComunicacion dbAccionDeMarketing = ctx.DbAccionDeMarketingComunicacions.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        var resultado = dbAccionDeMarketing.AccionDeMarketingEmailResultadoes.Where(l => l.Id == resultadoId).SingleOrDefault();
                        if (resultado != null)
                        {
                            ctx.DbAccionDeMarketingEmailResultadoes.DeleteObject(resultado);
                            ctx.SaveChanges();
                            tScope.Complete();
                        }
                    }
                }
            }
        }

        public void AddAmbitoAAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, List<int> puntoDeVentaIds)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;

                        List<DbPuntoDeVentas> dbPuntoDeVentaList = ctx.DbPuntoDeVentas.FilterLogicalRemoved().Where(l => puntoDeVentaIds.Contains(l.Id)).ToList();
                        foreach (var dbPuntoDeVenta in dbPuntoDeVentaList)
                        {
                            if (dbAccionDeMarketing.ListaDistribucions.Where(l => l.Id == dbPuntoDeVenta.Id).Count() == 0)
                            {
                                dbAccionDeMarketing.PuntoDeVentas.Add(dbPuntoDeVenta);
                            }
                        }

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public void EliminarAmbitoDeAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, int puntoDeVentaIds)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        var puntoDeVenta = dbAccionDeMarketing.PuntoDeVentas.Where(l => l.Id == puntoDeVentaIds).SingleOrDefault();
                        if (puntoDeVenta != null)
                        {
                            dbAccionDeMarketing.PuntoDeVentas.Remove(puntoDeVenta);
                            ctx.SaveChanges();
                            tScope.Complete();
                        }
                    }
                }
            }
        }

        public void AddAccionDeMarketingRelacionadaAAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, List<int> accionesDeMarketingRelacionadasIds)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;

                        List<DbAccionDeMarketing> dbAccionDeMarketingRelacionadaList = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(l => accionesDeMarketingRelacionadasIds.Contains(l.Id)).ToList();
                        foreach (var dbAccionDeMarketingRelacionada in dbAccionDeMarketingRelacionadaList)
                        {
                            if (dbAccionDeMarketing.AccionDeMarketings.Where(l => l.Id == dbAccionDeMarketingRelacionada.Id).Count() == 0)
                            {
                                dbAccionDeMarketing.AccionDeMarketings.Add(dbAccionDeMarketingRelacionada);
                            }
                        }

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public void AddCategoriasAContactos(ServiceOptions options, CustomerSearchParam searchParam, List<int> categoriasIds)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    List<DbCategoria> dbCategorias = ctx.DbCategorias.Where(c => categoriasIds.Contains(c.Id)).ToList();
                    int dummuy = 0;
                    IQueryable<DbContacto> query = GetCustomerSearchQuery(searchParam, ref dummuy, ctx);

                    List<int> contactosIds = query.Select(c => c.Id).ToList();

                    foreach (var contactoid in contactosIds)
                    {
                        var dbContacto = ctx.DbContactoes.Where(c => c.Id == contactoid).Single();
                        foreach (var dbCategoria in dbCategorias)
                        {
                            // Si el contacto no tiene la categoria la agrego
                            if (dbContacto.Categorias.Where(c => c.Id == dbCategoria.Id).Count() == 0)
                            {
                                dbContacto.Categorias.Add(dbCategoria);
                            }
                        }
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public void EliminarAccionDeMarketingRelacionadaDeAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, int accionDeMarketingRelacionadaId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        var accionDeMarketingRelacionada = dbAccionDeMarketing.AccionDeMarketings.Where(l => l.Id == accionDeMarketingRelacionadaId).SingleOrDefault();
                        if (accionDeMarketingRelacionada != null)
                        {
                            dbAccionDeMarketing.AccionDeMarketings.Remove(accionDeMarketingRelacionada);
                            ctx.SaveChanges();
                            tScope.Complete();
                        }
                    }
                }
            }
        }

        public void EliminarPuntoDeVentaRelacionadoDeAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, int puntoDeVentaId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        var accionDeMarketingRelacionada = dbAccionDeMarketing.PuntoDeVentas.Where(l => l.Id == puntoDeVentaId).SingleOrDefault();
                        if (accionDeMarketingRelacionada != null)
                        {
                            dbAccionDeMarketing.PuntoDeVentas.Remove(accionDeMarketingRelacionada);
                            ctx.SaveChanges();
                            tScope.Complete();
                        }
                    }
                }
            }
        }

        public void EliminarPlanDeMarketing(ServiceOptions options, int planDeMarketingId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbPlanDeMarketing dbPlanDeMarketing = ctx.DbPlanDeMarketings.FilterLogicalRemoved().Where(c => c.Id == planDeMarketingId).SingleOrDefault();
                    if (dbPlanDeMarketing != null)
                    {

                        if (dbPlanDeMarketing.AccionDeMarketings.AsQueryable().FilterLogicalRemoved().Count() > 0)
                        {
                            throw new Exception(LocalizationProvider.Instance["Exception.PlanDeMarketing.TieneAccionesAsociadas"]);
                        }

                        dbPlanDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbPlanDeMarketing.AuditUserNameModificacion = options.UserName;
                        dbPlanDeMarketing.Removed = true;

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public List<AccionDeMarketingPublicidad> GetAccionesDeMarketingPublicidad(AccionDeMarketingSearch search)
        {
            List<AccionDeMarketingPublicidad> accionDeMarketingList = new List<AccionDeMarketingPublicidad>();

            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    IQueryable<DbAccionDeMarketing> query = ctx.DbAccionDeMarketings.FilterLogicalRemoved();

                    query = BuildQueryAccionMarketing(search, query);

                    List<DbAccionDeMarketing> dbAccionDeMarketingList = query.ToList();
                    foreach (DbAccionDeMarketing dbAccionDeMarketing in dbAccionDeMarketingList)
                    {
                        if (dbAccionDeMarketing.AccionDeMarketingPublicidad != null)
                        {
                            AccionDeMarketingPublicidad accionDeMarketingPublicidad = new AccionDeMarketingPublicidad();
                            LoadAccionDeMarketing(search, accionDeMarketingPublicidad, dbAccionDeMarketing);

                            if (dbAccionDeMarketing.Estado != accionDeMarketingPublicidad.Estado)
                            {
                                dbAccionDeMarketing.Estado = accionDeMarketingPublicidad.Estado;
                                ctx.SaveChanges();
                            }

                            // Cargo la parte específica de publicidad                  
                            accionDeMarketingList.Add(accionDeMarketingPublicidad);
                        }
                    }

                    tScope.Complete();
                }
            }

            return accionDeMarketingList;
        }

        public List<AccionDeMarketingPromocion> GetAccionesDeMarketingPromocion(AccionDeMarketingSearch search)
        {
            List<AccionDeMarketingPromocion> accionDeMarketingList = new List<AccionDeMarketingPromocion>();
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    IQueryable<DbAccionDeMarketing> query = ctx.DbAccionDeMarketings.FilterLogicalRemoved();

                    query = BuildQueryAccionMarketing(search, query);

                    List<DbAccionDeMarketing> dbAccionDeMarketingList = query.ToList();
                    foreach (DbAccionDeMarketing dbAccionDeMarketing in dbAccionDeMarketingList)
                    {
                        AccionDeMarketingPromocion accionDeMarketingPromocion = new AccionDeMarketingPromocion();
                        LoadAccionDeMarketing(search, accionDeMarketingPromocion, dbAccionDeMarketing);

                        if (dbAccionDeMarketing.Estado != accionDeMarketingPromocion.Estado)
                        {
                            dbAccionDeMarketing.Estado = accionDeMarketingPromocion.Estado;
                            ctx.SaveChanges();
                        }

                        // Cargo la parte específica de promoción
                        var dbAccionMarketingPromocion = dbAccionDeMarketing.AccionDeMarketingPromocion;
                        if (dbAccionMarketingPromocion != null)
                        {
                            accionDeMarketingPromocion.TipoDescripcion = dbAccionMarketingPromocion.TipoDescripcion;
                            accionDeMarketingPromocion.LlegadaId = dbAccionMarketingPromocion.LlegadaId;
                            accionDeMarketingPromocion.TipoImplementacion = dbAccionMarketingPromocion.TipoImplementacion;
                            accionDeMarketingPromocion.EmpresaId = dbAccionDeMarketing.PlanDeMarketing.EmpresaId;
                            accionDeMarketingPromocion.Desde = dbAccionDeMarketing.FechaDesde;
                            accionDeMarketingPromocion.Hasta = dbAccionDeMarketing.FechaHasta;

                            if (dbAccionMarketingPromocion.AccionDeMarketingPromocionRegla != null)
                            {
                                accionDeMarketingPromocion.ReglaId = dbAccionMarketingPromocion.ReglaId;
                                EntityMapper.Map(dbAccionMarketingPromocion.AccionDeMarketingPromocionRegla, accionDeMarketingPromocion.AccionDeMarketingPromocionRegla);
                            }

                            accionDeMarketingList.Add(accionDeMarketingPromocion);
                        }
                    }

                    tScope.Complete();
                }
            }

            return accionDeMarketingList;
        }

        public List<AccionDeMarketingComunicacion> GetAccionesDeMarketingComunicacion(AccionDeMarketingSearch search)
        {

            List<AccionDeMarketingComunicacion> accionDeMarketingList = new List<AccionDeMarketingComunicacion>();
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    IQueryable<DbAccionDeMarketing> query = ctx.DbAccionDeMarketings.FilterLogicalRemoved();

                    query = BuildQueryAccionMarketing(search, query);

                    List<DbAccionDeMarketing> dbAccionDeMarketingList = query.ToList();
                    foreach (DbAccionDeMarketing dbAccionDeMarketing in dbAccionDeMarketingList)
                    {
                        AccionDeMarketingComunicacion accionDeMarketingComunicacion = new AccionDeMarketingComunicacion();
                        LoadAccionDeMarketing(search, accionDeMarketingComunicacion, dbAccionDeMarketing);

                        if (dbAccionDeMarketing.Estado != accionDeMarketingComunicacion.Estado)
                        {
                            dbAccionDeMarketing.Estado = accionDeMarketingComunicacion.Estado;
                            ctx.SaveChanges();
                        }

                        // Cargo la parte específica de comunicacion
                        var dbAccionMarketingComunicacion = ctx.DbAccionDeMarketingComunicacions.Where(c => c.Id == search.Id).Single();
                        accionDeMarketingComunicacion.TipoComunicacionId = dbAccionMarketingComunicacion.TipoComunicacionId;
                        accionDeMarketingComunicacion.TipoComunicacionNombre = dbAccionMarketingComunicacion.AccionDeMarketingComunicacionTipo.Nombre;
                        EntityMapper.Map(dbAccionMarketingComunicacion.AccionDeMarketingComunicacionTipo, accionDeMarketingComunicacion.TipoComunicacion);
                        EntityMapper.Map(dbAccionMarketingComunicacion.AccionDeMarketingComunicacionTipo.AccionDeMarketingComunicacionConfiguracion, accionDeMarketingComunicacion.TipoComunicacion.Configuracion);

                        //Tengo que cargar los resultados de marketing
                        if (search.LoadResultados)
                        {
                            foreach (var dbResultado in dbAccionMarketingComunicacion.AccionDeMarketingEmailResultadoes)
                            {
                                AccionDeMarketingEmailResultado resultadoMarketing = new AccionDeMarketingEmailResultado();
                                EntityMapper.Map(dbResultado, resultadoMarketing);
                                resultadoMarketing.Email = dbResultado.Contacto.Email;
                                resultadoMarketing.ContactoNombre = dbResultado.Contacto.Nombre;
                                resultadoMarketing.ContactoApellido = dbResultado.Contacto.Apellido;

                                accionDeMarketingComunicacion.Resultados.Add(resultadoMarketing);
                            }
                        }

                        accionDeMarketingList.Add(accionDeMarketingComunicacion);
                    }

                    tScope.Complete();
                }
            }

            return accionDeMarketingList;
        }

        public List<AccionDeMarketing> GetAccionesDeMarketing(ServiceOptions options, AccionDeMarketingSearch search)
        {
            List<AccionDeMarketing> accionDeMarketingList = new List<AccionDeMarketing>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbAccionDeMarketing> query = ctx.DbAccionDeMarketings.FilterLogicalRemoved();

                query = BuildQueryAccionMarketing(search, query);

                List<DbAccionDeMarketing> dbAccionDeMarketingList = query.ToList();
                foreach (DbAccionDeMarketing dbAccionDeMarketing in dbAccionDeMarketingList)
                {
                    AccionDeMarketing accionDeMarketing = new AccionDeMarketing();
                    LoadAccionDeMarketing(search, accionDeMarketing, dbAccionDeMarketing);
                    accionDeMarketingList.Add(accionDeMarketing);
                }
            }

            return accionDeMarketingList;
        }

        private void LoadAccionDeMarketing(AccionDeMarketingSearch search, AccionDeMarketing accionDeMarketing, DbAccionDeMarketing dbAccionDeMarketing)
        {
            //AccionDeMarketing accionDeMarketing = new AccionDeMarketing();
            LoadAccionDeMarketingBasicInfo(accionDeMarketing, dbAccionDeMarketing);

            if (search.LoadAmbitos)
            {
                foreach (var dbAmbito in dbAccionDeMarketing.PuntoDeVentas)
                {
                    LoadAmbito(accionDeMarketing, dbAmbito);
                }
            }

            if (search.LoadAccionesDeMarketingRelacionadas)
            {
                foreach (var dbAccionDeMarketingRelacionada in dbAccionDeMarketing.AccionDeMarketings)
                {
                    AccionDeMarketing accionDeMarketigRelacionada = new AccionDeMarketing();
                    LoadAccionDeMarketingBasicInfo(accionDeMarketigRelacionada, dbAccionDeMarketingRelacionada);
                    accionDeMarketing.AccionesDeMarketingRelacionadasList.Add(accionDeMarketigRelacionada);
                }
            }

            if (search.LoadListasDeDistribucion)
            {
                foreach (var dbListaDeDistribucion in dbAccionDeMarketing.ListaDistribucions)
                {
                    ListaDeDistribucion listaDeDistribucion = new ListaDeDistribucion();
                    LoadListaDistribucionFromDb(listaDeDistribucion, dbListaDeDistribucion);
                    accionDeMarketing.ListaDeDistribucionList.Add(listaDeDistribucion);
                }
            }

            //if (search.LoadResultados)
            //{
            //    foreach (var dbResultado in dbAccionDeMarketing.AccionDeMarketingResultadoes)
            //    {
            //        AccionDeMarketingEmailResultado resultadoMarketing = new AccionDeMarketingEmailResultado();
            //        LoadAccionDeMarketingResultados(resultadoMarketing, dbResultado);
            //        accionDeMarketing.Resultados.Add(resultadoMarketing);
            //    }
            //}            
        }

        private static IQueryable<DbAccionDeMarketing> BuildQueryAccionMarketing(AccionDeMarketingSearch search, IQueryable<DbAccionDeMarketing> query)
        {
            query = query.FilterLogicalRemoved();

            if (search.Id.HasValue)
            {
                query = query.Where(c => c.Id == search.Id.Value);
            }
            else
            {
                query = query.Where(p => p.PlanDeMarketing.EmpresaId == search.EmpresaId);

                if (search.PlanDeMarketingId.HasValue)
                {
                    query = query.Where(c => c.PlanDeMarketingId == search.PlanDeMarketingId.Value);
                }

                if (!String.IsNullOrEmpty(search.NombreLike))
                {
                    query = query.Where(c => c.Nombre.Contains(search.NombreLike));
                }

                if (!String.IsNullOrEmpty(search.DescripcionLike))
                {
                    query = query.Where(c => c.Descripcion.Contains(search.DescripcionLike));
                }

                if (!String.IsNullOrEmpty(search.CodigoLike))
                {
                    query = query.Where(c => c.CodigoParaPDV.Contains(search.CodigoLike));
                }

                if (search.FechaEventoDesde.HasValue)
                {
                    query = query.Where(c => c.FechaDesde >= search.FechaEventoDesde.Value);
                }

                if (search.FechaEventoHasta.HasValue)
                {
                    query = query.Where(c => c.FechaHasta <= search.FechaEventoHasta.Value);
                }

                if (search.DiscriminadorIdList.Count > 0)
                {
                    query = query.Where(c => search.DiscriminadorIdList.Contains(c.Discriminador));
                }

                if (search.PlanDeMarketingId.HasValue)
                {
                    query = query.Where(c => c.PlanDeMarketingId == search.PlanDeMarketingId.Value);
                }

                if (search.EstadoList.Count > 0)
                {
                    query = query.Where(c => c.Estado.HasValue && search.EstadoList.Contains(c.Estado.Value));
                }

                //if (search.Ambitos.Count > 0)
                //{
                //    query = query.Where(c => c.PuntoDeVentas.Select(p => p.Id).Contains());                        
                //}       
            }
            return query;
        }

        public List<AccionDeMarketingEmailResultado> SaveResultadosEmailAccionDeMarketing(ServiceOptions options, int accionDeMarketingComunicacionId, List<AccionDeMarketingEmailResultado> resultadoList)
        {
            DateTime now = DateTime.Now;
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                var dbAccionDeMarketing = ctx.DbAccionDeMarketingComunicacions.Where(a => a.Id == accionDeMarketingComunicacionId).Single();

                foreach (var emailResultado in resultadoList)
                {
                    // Tengo que conseguir el usuario
                    var dbContact = ctx.DbContactoes.Where(c => c.EmpresaId == options.CompanyId && c.Email == emailResultado.Email).SingleOrDefault();

                    if (dbContact != null)
                    {
                        emailResultado.ContactoId = dbContact.Id;
                        emailResultado.ContactoNombre = dbContact.Nombre;
                        emailResultado.ContactoApellido = dbContact.Apellido;

                        DbAccionDeMarketingEmailResultado dbEmailResultado = ctx.DbAccionDeMarketingEmailResultadoes.Where(r => r.AccionDeMarketingId == accionDeMarketingComunicacionId && r.ContactoId == emailResultado.ContactoId).SingleOrDefault();

                        if (dbEmailResultado == null)
                        {
                            dbEmailResultado = new DbAccionDeMarketingEmailResultado();
                            dbAccionDeMarketing.AccionDeMarketingEmailResultadoes.Add(dbEmailResultado);
                        }
                        else
                        {
                            emailResultado.Mensaje += LocalizationProvider.Instance["Be.ResultadosEmailMarketing.ResultadoActualizado"];
                        }

                        EntityMapper.Map(emailResultado, dbEmailResultado, "Id");
                        dbEmailResultado.AccionDeMarketingId = dbAccionDeMarketing.Id;
                        dbEmailResultado.FechaAltaRegistro = now;
                        emailResultado.FechaAltaRegistro = now;

                        try
                        {
                            ctx.SaveChanges();
                            emailResultado.Id = dbEmailResultado.Id;
                        }
                        catch (Exception ex)
                        {
                            emailResultado.Mensaje += ex.Message;
                        }
                    }
                    else
                    {
                        emailResultado.Mensaje += LocalizationProvider.Instance["Be.ResultadosEmailMarketing.EmailSinContacto"];
                    }
                }
            }

            return resultadoList;
        }

        private static void LoadAmbito(AccionDeMarketing accionDeMarketing, DbPuntoDeVentas dbAmbito)
        {
            MaestroBase ambito = new MaestroBase();
            ambito.Id = dbAmbito.Id;
            ambito.Nombre = string.Format("{0}({1})", dbAmbito.Nombre, dbAmbito.CodigoExterno);
            accionDeMarketing.AmbitoList.Add(ambito);
        }

        private void LoadAccionDeMarketingResultados(AccionDeMarketingEmailResultado accionDeMarketingResultado, DbAccionDeMarketingEmailResultado dbAccionDeMarketingResultado)
        {
            accionDeMarketingResultado.ContactoId = dbAccionDeMarketingResultado.ContactoId;
            accionDeMarketingResultado.EmailAbierto = dbAccionDeMarketingResultado.EmailAbierto;
            accionDeMarketingResultado.EmailFechaApertura = dbAccionDeMarketingResultado.EmailFechaApertura;
            accionDeMarketingResultado.Email = dbAccionDeMarketingResultado.Contacto.Email;
            accionDeMarketingResultado.ContactoNombre = dbAccionDeMarketingResultado.Contacto.Nombre;
            accionDeMarketingResultado.ContactoApellido = dbAccionDeMarketingResultado.Contacto.Apellido;
        }

        public AccionDeMarketingPromocion SaveAccionDeMarketingPromocion(ServiceOptions options, AccionDeMarketingPromocion accionDeMarketing)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketing.Id).SingleOrDefault();
                    if (dbAccionDeMarketing == null)
                    {
                        dbAccionDeMarketing = new DbAccionDeMarketing();
                        ctx.DbAccionDeMarketings.AddObject(dbAccionDeMarketing);
                        dbAccionDeMarketing.AccionDeMarketingPromocion = new DbAccionDeMarketingPromocion();
                        dbAccionDeMarketing.AuditFechaCreacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameCreacion = options.UserName;
                    }
                    else
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;
                    }

                    dbAccionDeMarketing.AccionDeMarketingPromocion.TipoDescripcion = accionDeMarketing.TipoDescripcion;
                    dbAccionDeMarketing.AccionDeMarketingPromocion.ReglaId = accionDeMarketing.ReglaId;
                    dbAccionDeMarketing.AccionDeMarketingPromocion.LlegadaId = accionDeMarketing.LlegadaId;

                    dbAccionDeMarketing.PlanDeMarketingId = accionDeMarketing.PlanDeMarketingId;
                    dbAccionDeMarketing.Nombre = accionDeMarketing.Nombre;
                    dbAccionDeMarketing.Responsable = accionDeMarketing.Responsable;
                    dbAccionDeMarketing.Descripcion = accionDeMarketing.Descripcion;
                    dbAccionDeMarketing.CodigoParaPDV = accionDeMarketing.CodigoParaPDV;
                    dbAccionDeMarketing.FechaDesde = accionDeMarketing.FechaDesde;
                    dbAccionDeMarketing.FechaHasta = accionDeMarketing.FechaHasta;
                    dbAccionDeMarketing.Discriminador = accionDeMarketing.Discriminador;
                    dbAccionDeMarketing.Inversion = accionDeMarketing.Inversion;
                    dbAccionDeMarketing.ROIDinero = accionDeMarketing.ROIDinero;
                    dbAccionDeMarketing.ROIPorcentaje = accionDeMarketing.ROIPorcentaje;
                    dbAccionDeMarketing.EficaciaEsperada = accionDeMarketing.EficaciaEsperada;

                    AnalizarEstadoAccionDeMarketing(accionDeMarketing);
                    dbAccionDeMarketing.Estado = accionDeMarketing.Estado;

                    ctx.SaveChanges();
                    tScope.Complete();
                    accionDeMarketing.Id = dbAccionDeMarketing.Id;
                }
            }

            return accionDeMarketing;
        }

        public AccionDeMarketingPublicidad SaveAccionDeMarketingPublicidad(ServiceOptions options, AccionDeMarketingPublicidad accionDeMarketing)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketing.Id).SingleOrDefault();
                    if (dbAccionDeMarketing == null)
                    {
                        dbAccionDeMarketing = new DbAccionDeMarketing();
                        ctx.DbAccionDeMarketings.AddObject(dbAccionDeMarketing);
                        dbAccionDeMarketing.AccionDeMarketingPublicidad = new DbAccionDeMarketingPublicidad();
                        dbAccionDeMarketing.AuditFechaCreacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameCreacion = options.UserName;
                    }
                    else
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;
                    }

                    dbAccionDeMarketing.PlanDeMarketingId = accionDeMarketing.PlanDeMarketingId;
                    dbAccionDeMarketing.Nombre = accionDeMarketing.Nombre;
                    dbAccionDeMarketing.Descripcion = accionDeMarketing.Descripcion;
                    dbAccionDeMarketing.Responsable = accionDeMarketing.Responsable;
                    dbAccionDeMarketing.CodigoParaPDV = accionDeMarketing.CodigoParaPDV;
                    dbAccionDeMarketing.FechaDesde = accionDeMarketing.FechaDesde;
                    dbAccionDeMarketing.FechaHasta = accionDeMarketing.FechaHasta;
                    dbAccionDeMarketing.Discriminador = accionDeMarketing.Discriminador;
                    dbAccionDeMarketing.Inversion = accionDeMarketing.Inversion;
                    dbAccionDeMarketing.ROIDinero = accionDeMarketing.ROIDinero;
                    dbAccionDeMarketing.ROIPorcentaje = accionDeMarketing.ROIPorcentaje;
                    dbAccionDeMarketing.EficaciaEsperada = accionDeMarketing.EficaciaEsperada;

                    AnalizarEstadoAccionDeMarketing(accionDeMarketing);
                    dbAccionDeMarketing.Estado = accionDeMarketing.Estado;

                    ctx.SaveChanges();
                    tScope.Complete();
                    accionDeMarketing.Id = dbAccionDeMarketing.Id;
                }
            }

            return accionDeMarketing;
        }

        public AccionDeMarketingComunicacion SaveAccionDeMarketingComunicacion(ServiceOptions options, AccionDeMarketingComunicacion accionDeMarketing)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketing.Id).SingleOrDefault();
                    if (dbAccionDeMarketing == null)
                    {
                        dbAccionDeMarketing = new DbAccionDeMarketing();
                        ctx.DbAccionDeMarketings.AddObject(dbAccionDeMarketing);
                        dbAccionDeMarketing.AccionDeMarketingComunicacion = new DbAccionDeMarketingComunicacion();
                        dbAccionDeMarketing.AuditFechaCreacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameCreacion = options.UserName;
                    }
                    else
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;
                    }

                    dbAccionDeMarketing.AccionDeMarketingComunicacion.TipoComunicacionId = accionDeMarketing.TipoComunicacionId;
                    dbAccionDeMarketing.PlanDeMarketingId = accionDeMarketing.PlanDeMarketingId;
                    dbAccionDeMarketing.Nombre = accionDeMarketing.Nombre;
                    dbAccionDeMarketing.Descripcion = accionDeMarketing.Descripcion;
                    dbAccionDeMarketing.Responsable = accionDeMarketing.Responsable;
                    dbAccionDeMarketing.CodigoParaPDV = accionDeMarketing.CodigoParaPDV;
                    dbAccionDeMarketing.FechaDesde = accionDeMarketing.FechaDesde;
                    dbAccionDeMarketing.FechaHasta = accionDeMarketing.FechaHasta;
                    dbAccionDeMarketing.Discriminador = accionDeMarketing.Discriminador;
                    dbAccionDeMarketing.Inversion = accionDeMarketing.Inversion;
                    dbAccionDeMarketing.ROIDinero = accionDeMarketing.ROIDinero;
                    dbAccionDeMarketing.ROIPorcentaje = accionDeMarketing.ROIPorcentaje;
                    dbAccionDeMarketing.EficaciaEsperada = accionDeMarketing.EficaciaEsperada;

                    AnalizarEstadoAccionDeMarketing(accionDeMarketing);
                    dbAccionDeMarketing.Estado = accionDeMarketing.Estado;

                    ctx.SaveChanges();
                    tScope.Complete();
                    accionDeMarketing.Id = dbAccionDeMarketing.Id;
                }
            }

            return accionDeMarketing;
        }

        public AccionDeMarketing SaveAccionDeMarketing(ServiceOptions options, AccionDeMarketing accionDeMarketing)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketing.Id).SingleOrDefault();
                    if (dbAccionDeMarketing == null)
                    {
                        dbAccionDeMarketing = new DbAccionDeMarketing();
                        ctx.DbAccionDeMarketings.AddObject(dbAccionDeMarketing);
                        dbAccionDeMarketing.AuditFechaCreacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameCreacion = options.UserName;
                    }
                    else
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;
                    }

                    dbAccionDeMarketing.PlanDeMarketingId = accionDeMarketing.PlanDeMarketingId;
                    dbAccionDeMarketing.Nombre = accionDeMarketing.Nombre;
                    dbAccionDeMarketing.Descripcion = accionDeMarketing.Descripcion;

                    AnalizarEstadoAccionDeMarketing(accionDeMarketing);
                    dbAccionDeMarketing.Estado = accionDeMarketing.Estado;
                    //dbAccionDeMarketing.Codigo = accionDeMarketing.CodigoParaPDV;
                    //dbAccionDeMarketing.FechaEventoDesde = accionDeMarketing.FechaEventoDesde;
                    //dbAccionDeMarketing.FechaEventoHasta = accionDeMarketing.FechaEventoHasta;
                    //dbAccionDeMarketing.Discriminador = accionDeMarketing.Discriminador;
                    //dbAccionDeMarketing.TipoId = accionDeMarketing.TipoAccionDeMarketingId;                    

                    ctx.SaveChanges();
                    tScope.Complete();
                    accionDeMarketing.Id = dbAccionDeMarketing.Id;
                }
            }

            return accionDeMarketing;
        }

        public void CambiarEstadoAAccionDeMarketing(ServiceOptions options, int accionDeMarketingId, int estado)
        {
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                if (dbAccionDeMarketing != null)
                {
                    dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                    dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;
                    dbAccionDeMarketing.Estado = estado;

                    ctx.SaveChanges();
                }
            }
        }

        public void CambiarEstadoAPlanDeMarketing(ServiceOptions options, int planDeMarketingId, int estado)
        {
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                DbPlanDeMarketing dbPlanDeMarketing = ctx.DbPlanDeMarketings.FilterLogicalRemoved().Where(c => c.Id == planDeMarketingId).SingleOrDefault();
                if (dbPlanDeMarketing != null)
                {
                    dbPlanDeMarketing.AuditFechaModificacion = DateTime.Now;
                    dbPlanDeMarketing.AuditUserNameModificacion = options.UserName;
                    dbPlanDeMarketing.Estado = estado;

                    ctx.SaveChanges();
                }
            }
        }

        public void EliminarAccionDeMarketing(ServiceOptions options, int accionDeMarketingId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbAccionDeMarketing dbAccionDeMarketing = ctx.DbAccionDeMarketings.FilterLogicalRemoved().Where(c => c.Id == accionDeMarketingId).SingleOrDefault();
                    if (dbAccionDeMarketing != null)
                    {
                        dbAccionDeMarketing.AuditFechaModificacion = DateTime.Now;
                        dbAccionDeMarketing.AuditUserNameModificacion = options.UserName;
                        dbAccionDeMarketing.Removed = true;

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public List<ListaDeDistribucion> GetListaDeDistribucion(ServiceOptions options, ListaDistribucionSearch search)
        {
            List<ListaDeDistribucion> listaDeDistribucionList = new List<ListaDeDistribucion>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbListaDistribucion> query = ctx.DbListaDistribucions.FilterLogicalRemoved();

                if (search.Id.HasValue)
                {
                    query = query.Where(c => c.Id == search.Id.Value);
                }
                else
                {
                    query = query.Where(c => c.EmpresaId == search.EmpresaId);

                    if (!string.IsNullOrEmpty(search.NombreLike))
                    {
                        query = query.Where(c => c.Nombre.Contains(search.NombreLike));
                    }
                }

                List<DbListaDistribucion> dbListaDistribucionList = query.ToList();
                foreach (DbListaDistribucion dbListaDistribucion in dbListaDistribucionList)
                {
                    ListaDeDistribucion listaDistribucion = new ListaDeDistribucion();
                    LoadListaDistribucionFromDb(listaDistribucion, dbListaDistribucion);
                    if (search.LoadContactos)
                    {
                        foreach (var dbContacto in dbListaDistribucion.Contactoes)
                        {
                            Cliente customer = new Cliente();
                            LoadCustomerVeryBasicInfo(dbContacto, customer);
                            listaDistribucion.ContactoList.Add(customer);
                        }
                    }

                    listaDeDistribucionList.Add(listaDistribucion);
                }
            }

            return listaDeDistribucionList;
        }

        public ListaDeDistribucion SaveListaDeDistribucion(ServiceOptions options, ListaDeDistribucion listaDistribucion)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbListaDistribucion dbListaDeDistribucion = ctx.DbListaDistribucions.FilterLogicalRemoved().Where(c => c.Id == listaDistribucion.Id).SingleOrDefault();
                    if (dbListaDeDistribucion == null)
                    {
                        dbListaDeDistribucion = new DbListaDistribucion();
                        ctx.DbListaDistribucions.AddObject(dbListaDeDistribucion);
                        dbListaDeDistribucion.EmpresaId = listaDistribucion.EmpresaId;
                        dbListaDeDistribucion.AuditFechaCreacion = DateTime.Now;
                        dbListaDeDistribucion.AuditUserNameCreacion = options.UserName;
                    }
                    else
                    {
                        dbListaDeDistribucion.AuditFechaModificacion = DateTime.Now;
                        dbListaDeDistribucion.AuditUserNameModificacion = options.UserName;
                    }

                    dbListaDeDistribucion.Nombre = listaDistribucion.Nombre;
                    dbListaDeDistribucion.Estado = listaDistribucion.Estado;
                    dbListaDeDistribucion.Descripcion = listaDistribucion.Descripcion;

                    if (listaDistribucion.UpdateContactoList)
                    {
                        dbListaDeDistribucion.Contactoes.Clear();
                        var contactosIdsToUpdate = listaDistribucion.ContactoList.Select(c => c.Id).ToList();
                        var dbContactosToUpdate = ctx.DbContactoes.Where(c => contactosIdsToUpdate.Contains(c.Id)).ToList();

                        foreach (var dbContatoToUpdate in dbContactosToUpdate)
                        {
                            dbListaDeDistribucion.Contactoes.Add(dbContatoToUpdate);
                        }
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                    listaDistribucion.UpdateContactoList = false;
                    listaDistribucion.Id = dbListaDeDistribucion.Id;
                }
            }

            return listaDistribucion;
        }

        public void EliminarListaDeDistribucion(ServiceOptions options, int listaDistribucionId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbListaDistribucion dbListaDeDistribucion = ctx.DbListaDistribucions.FilterLogicalRemoved().Where(c => c.Id == listaDistribucionId).SingleOrDefault();

                    if (dbListaDeDistribucion != null)
                    {
                        dbListaDeDistribucion.AuditFechaModificacion = DateTime.Now;
                        dbListaDeDistribucion.AuditUserNameModificacion = options.UserName;
                        dbListaDeDistribucion.Removed = true;

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public void EliminarContactoDeListaDeDistribucion(ServiceOptions options, int listaDistribucionId, int contactoId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    DbListaDistribucion dbListaDeDistribucion = ctx.DbListaDistribucions.FilterLogicalRemoved().Where(c => c.Id == listaDistribucionId).SingleOrDefault();
                    DbContacto dbContacto = ctx.DbContactoes.FilterLogicalRemoved().Where(c => c.Id == contactoId).SingleOrDefault();
                    if (dbListaDeDistribucion != null && dbContacto != null)
                    {
                        dbListaDeDistribucion.Contactoes.Remove(dbContacto);

                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }
        }

        public void ActivarEntidad(ServiceOptions options, string entidad, int estado, int entidadId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    if (entidad == typeof(Cliente).Name)
                    {
                        var dbContacto = ctx.DbContactoes.Where(c => c.Id == entidadId).SingleOrDefault();
                        if (dbContacto != null)
                        {
                            EstadoCliente estadoOriginal = EstadoCliente.Activo;
                            if (dbContacto.Estado.HasValue)
                            {
                                estadoOriginal = (EstadoCliente)dbContacto.Estado.Value;
                            }

                            EstadoCliente estadoFinal = (EstadoCliente)estado;

                            dbContacto.Estado = estado;
                            dbContacto.AuditFechaModificacion = DateTime.Now;
                            dbContacto.AuditUserNameModificacion = options.UserName;

                            // Genero registro en bitácora CRMINT-141
                            //return DescriptionKey.GetEnumDescription(enumParam);
                            string mensaje = string.Format(LocalizationProvider.Instance["Bo.ContactoBitacora.CambioEstado"], DescriptionKey.GetEnumDescription(estadoOriginal), DescriptionKey.GetEnumDescription(estadoFinal));
                            dbContacto.ContactoBitacoras.Add(CrearBitacoraCambioDeEstado(mensaje, options.UserName));
                        }
                    }
                    else if (entidad == typeof(ListaDeDistribucion).Name)
                    {
                        var dbListaDistribucion = ctx.DbListaDistribucions.Where(l => l.Id == entidadId).SingleOrDefault();
                        if (dbListaDistribucion != null)
                        {
                            dbListaDistribucion.Estado = estado;
                            dbListaDistribucion.AuditFechaModificacion = DateTime.Now;
                            dbListaDistribucion.AuditUserNameModificacion = options.UserName;
                        }
                    }
                    else if (entidad == typeof(PlanDeMarketing).Name)
                    {
                        var dbPlanDeMarketing = ctx.DbPlanDeMarketings.Where(c => c.Id == entidadId).SingleOrDefault();
                        if (dbPlanDeMarketing != null)
                        {
                            dbPlanDeMarketing.Estado = estado;
                            dbPlanDeMarketing.AuditFechaModificacion = DateTime.Now;
                            dbPlanDeMarketing.AuditUserNameModificacion = options.UserName;
                        }
                    }
                    else if (entidad == typeof(PuntoDeVenta).Name)
                    {
                        var dbPuntoDeVenta = ctx.DbPuntoDeVentas.Where(c => c.Id == entidadId).SingleOrDefault();
                        if (dbPuntoDeVenta != null)
                        {
                            dbPuntoDeVenta.Activo = estado == 1;
                            dbPuntoDeVenta.AuditFechaModificacion = DateTime.Now;
                            dbPuntoDeVenta.AuditUserNameModificacion = options.UserName;
                        }
                    }
                    //else if (entidad == typeof(CampaniaInstancia).Name)
                    //{
                    //    var dbCampaniaInstancia = ctx.DbCampaniaInstancias.Where(c => c.Id == entidadId).SingleOrDefault();
                    //    if (dbCampaniaInstancia != null)
                    //    {
                    //        dbCampaniaInstancia.Estado = estado;
                    //        dbCampaniaInstancia.AuditFechaModificacion = DateTime.Now;
                    //        dbCampaniaInstancia.AuditUserNameModificacion = options.UserName;
                    //    }
                    //}

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public AccionDeMarketingComunicacionConfiguracion SaveAccionMarketingConfiguracion(ServiceOptions options, AccionDeMarketingComunicacionConfiguracion configuracion)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbConfiguracionMarketing = ctx.DbAccionDeMarketingComunicacionConfiguracions.Where(c => c.Id == configuracion.Id).SingleOrDefault();
                    if (dbConfiguracionMarketing == null)
                    {
                        dbConfiguracionMarketing = new DbAccionDeMarketingComunicacionConfiguracion();
                        ctx.DbAccionDeMarketingComunicacionConfiguracions.AddObject(dbConfiguracionMarketing);
                        dbConfiguracionMarketing.AuditFechaCreacion = now;
                        dbConfiguracionMarketing.AuditUserNameCreacion = options.UserName;
                    }

                    EntityMapper.Map(configuracion, dbConfiguracionMarketing);
                    dbConfiguracionMarketing.AuditFechaModificacion = now;
                    dbConfiguracionMarketing.AuditUserNameModificacion = options.UserName;

                    ctx.SaveChanges();
                    tScope.Complete();
                    configuracion.Id = dbConfiguracionMarketing.Id;
                }
            }

            return configuracion;
        }

        public List<AccionDeMarketingComunicacionConfiguracion> GetAccionesMarketingConfiguracion(ServiceOptions options, ConfiguracionAccionMarketingSearch search)
        {
            List<AccionDeMarketingComunicacionConfiguracion> configuracionList = new List<AccionDeMarketingComunicacionConfiguracion>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbAccionDeMarketingComunicacionConfiguracion> query = ctx.DbAccionDeMarketingComunicacionConfiguracions.FilterLogicalRemoved().Where(e => e.EmpresaId == search.EmpresaId);

                if (!String.IsNullOrEmpty(search.Id))
                {
                    query = query.Where(s => s.Id == search.Id);
                }
                else
                {
                    if (!String.IsNullOrEmpty(search.NombreLike))
                    {
                        query = query.Where(s => s.Nombre.Contains(search.NombreLike));
                    }
                }

                foreach (var dbConfig in query)
                {
                    AccionDeMarketingComunicacionConfiguracion config = new AccionDeMarketingComunicacionConfiguracion();
                    EntityMapper.Map(dbConfig, config);
                    configuracionList.Add(config);
                }
            }

            return configuracionList;
        }

        public void EliminarAccionMarketingConfiguracion(ServiceOptions options, string configuracionId)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbConfiguracionMarketing = ctx.DbAccionDeMarketingComunicacionConfiguracions.Where(c => c.Id == configuracionId).SingleOrDefault();
                    if (dbConfiguracionMarketing != null)
                    {
                        if (!dbConfiguracionMarketing.Sistema.HasValue || !dbConfiguracionMarketing.Sistema.Value)
                        {
                            dbConfiguracionMarketing.AuditFechaModificacion = now;
                            dbConfiguracionMarketing.AuditUserNameModificacion = options.UserName;
                            dbConfiguracionMarketing.Removed = true;
                        }
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public List<PuntoDeVenta> GetPuntoDeVentaDto(ServiceOptions options, PuntoDeVentaSearch search)
        {
            DateTime now = DateTime.Now;
            List<PuntoDeVenta> puntoVentaList = new List<PuntoDeVenta>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbPuntoDeVentas> query = ctx.DbPuntoDeVentas.FilterLogicalRemoved().Where(c => c.EmpresaId == search.EmpresaId);

                if (search.PuntoDeVentaId.HasValue)
                {
                    query = query.Where(c => c.Id == search.PuntoDeVentaId.Value);
                }
                else
                {
                    if (!String.IsNullOrEmpty(search.Nombre))
                    {
                        query = query.Where(c => c.Nombre.Contains(search.Nombre));
                    }

                    if (!String.IsNullOrEmpty(search.CodigoExterno))
                    {
                        query = query.Where(c => c.CodigoExterno.Contains(search.CodigoExterno));
                    }

                    if (search.Activo.HasValue)
                    {
                        query = query.Where(c => c.Activo == search.Activo.Value);
                    }

                    if (search.Outlet.HasValue)
                    {
                        query = query.Where(c => c.Outlet == search.Outlet.Value);
                    }
                }

                query = query.OrderBy(p => p.Nombre);

                foreach (var dbpto in query)
                {
                    PuntoDeVenta ptoVta = new PuntoDeVenta();
                    EntityMapper.Map(dbpto, ptoVta);

                    if (search.LoadSubPuntos)
                    {
                        foreach (var dbSubPtoVta in dbpto.SubPuntoDeVentas)
                        {
                            SubPuntoDeVenta subPtoVta = new SubPuntoDeVenta();
                            EntityMapper.Map(dbSubPtoVta, subPtoVta);
                            ptoVta.SubPuntosDeVenta.Add(subPtoVta);
                        }
                    }

                    puntoVentaList.Add(ptoVta);
                }
            }

            return puntoVentaList;
        }

        public PuntoDeVenta SavePuntoDeVentaDto(ServiceOptions options, PuntoDeVenta ptoVta)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbPtoVta = ctx.DbPuntoDeVentas.Where(c => c.Id == ptoVta.Id).SingleOrDefault();
                    if (dbPtoVta == null)
                    {
                        dbPtoVta = new DbPuntoDeVentas();
                        ctx.DbPuntoDeVentas.AddObject(dbPtoVta);
                        dbPtoVta.AuditFechaCreacion = now;
                        dbPtoVta.AuditUserNameCreacion = options.UserName;
                    }

                    EntityMapper.Map(ptoVta, dbPtoVta, "Id");
                    dbPtoVta.AuditFechaModificacion = now;
                    dbPtoVta.AuditUserNameModificacion = options.UserName;

                    ctx.SaveChanges();
                    tScope.Complete();
                    ptoVta.Id = dbPtoVta.Id;
                }
            }

            return ptoVta;
        }

        public void EliminarPuntoDeVentaDto(ServiceOptions options, int puntoDeVentaId)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbPtoVta = ctx.DbPuntoDeVentas.Where(c => c.Id == puntoDeVentaId).SingleOrDefault();
                    if (dbPtoVta == null)
                    {
                        dbPtoVta.AuditFechaModificacion = now;
                        dbPtoVta.AuditUserNameModificacion = options.UserName;
                        dbPtoVta.Removed = true;
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public List<Pais> GetPaisesDto(ServiceOptions options, PaisSearch search)
        {
            DateTime now = DateTime.Now;
            List<Pais> paisList = new List<Pais>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbPai> query = ctx.DbPais.FilterLogicalRemoved().OrderBy(p => p.Nombre);

                if (search.Id.HasValue)
                {
                    query = query.Where(c => c.Id == search.Id.Value);
                }
                else
                {
                    if (!String.IsNullOrEmpty(search.NombreLike))
                    {
                        query = query.Where(c => c.Nombre.Contains(search.NombreLike));
                    }
                }

                foreach (var dbPais in query)
                {
                    Pais pais = new Pais();
                    EntityMapper.Map(dbPais, pais, "Provincias");

                    // Uso la traducción del nombre
                    pais.Nombre = LocalizationProvider.Instance[dbPais.LocalizationKey];

                    // Mapear las provincas         
                    if (search.LoadProvincia)
                    {
                        foreach (var dbProvincia in dbPais.Provincias.OrderBy(p => p.Nombre))
                        {
                            Provincia provincia = new Provincia();
                            EntityMapper.Map(dbProvincia, provincia);
                            provincia.Nombre = LocalizationProvider.Instance[dbProvincia.LocalizationKey];
                            pais.Provincias.Add(provincia);
                        }
                    }

                    paisList.Add(pais);
                }
            }

            return paisList;
        }

        public Pais SavePaisDto(ServiceOptions options, Pais pais)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbPais = ctx.DbPais.Where(c => c.Id == pais.Id).SingleOrDefault();
                    if (dbPais == null)
                    {
                        dbPais = new DbPai();
                        ctx.DbPais.AddObject(dbPais);
                        dbPais.Id = pais.Id;
                        // Localización
                        dbPais.LocalizationKey = "Pais_" + pais.Nombre;

                        var lenguajes = ctx.DbLenguajes.ToList();

                        DbPalabrasClaveAplicacion pcApp = new DbPalabrasClaveAplicacion();
                        pcApp.Id = dbPais.LocalizationKey;
                        pcApp.Nombre = pais.Nombre;
                        pcApp.EsJavascript = false;
                        ctx.DbPalabrasClaveAplicacions.AddObject(pcApp);
                        foreach (var leng in lenguajes)
                        {
                            DbPalabrasClaveAplicacionLenguaje appLen = new DbPalabrasClaveAplicacionLenguaje();
                            pcApp.PalabrasClaveAplicacionLenguajes.Add(appLen);
                            appLen.ClaveId = pcApp.Id;
                            appLen.LenguajeId = leng.Id;
                            appLen.Traduccion = pais.Nombre; // x defecto
                        }
                    }

                    EntityMapper.Map(pais, dbPais, "Id", "Provincias");

                    ctx.SaveChanges();
                    tScope.Complete();
                    pais.Id = dbPais.Id;
                }
            }

            return pais;
        }

        public void EliminarPaisDto(ServiceOptions options, int paisId)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbPais = ctx.DbPais.Where(c => c.Id == paisId).SingleOrDefault();
                    if (dbPais != null)
                    {
                        var provinciaList = dbPais.Provincias.ToList();
                        foreach (var dbProvincia in provinciaList)
                        {
                            ctx.DbProvincias.DeleteObject(dbProvincia);
                        }

                        ctx.DbPais.DeleteObject(dbPais);
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public List<Provincia> GetProvinciasDto(ServiceOptions options, MaestroBaseSearch search)
        {
            DateTime now = DateTime.Now;
            List<Provincia> provinciaList = new List<Provincia>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbProvincia> query = ctx.DbProvincias.FilterLogicalRemoved();

                if (search.Id.HasValue)
                {
                    query = query.Where(c => c.Id == search.Id.Value);
                }
                else
                {
                    if (!String.IsNullOrEmpty(search.NombreLike))
                    {
                        query = query.Where(c => c.Nombre.Contains(search.NombreLike));
                    }
                }

                foreach (var dbProvincia in query)
                {
                    Provincia provincia = new Provincia();
                    EntityMapper.Map(dbProvincia, provincia);
                    provinciaList.Add(provincia);
                }
            }

            return provinciaList;
        }

        public Provincia SaveProvinciaDto(ServiceOptions options, Provincia provincia)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbProvincia = ctx.DbProvincias.Where(c => c.Id == provincia.Id).SingleOrDefault();
                    if (dbProvincia == null)
                    {
                        dbProvincia = new DbProvincia();
                        ctx.DbProvincias.AddObject(dbProvincia);
                        dbProvincia.Id = provincia.Id;

                        dbProvincia.LocalizationKey = string.Format("Pais_{0}Provincia_{1}", provincia.PaisId, provincia.Nombre);

                        var lenguajes = ctx.DbLenguajes.ToList();

                        DbPalabrasClaveAplicacion pcApp = new DbPalabrasClaveAplicacion();
                        pcApp.Id = dbProvincia.LocalizationKey;
                        pcApp.Nombre = provincia.Nombre;
                        pcApp.EsJavascript = false;
                        ctx.DbPalabrasClaveAplicacions.AddObject(pcApp);
                        foreach (var leng in lenguajes)
                        {
                            DbPalabrasClaveAplicacionLenguaje appLen = new DbPalabrasClaveAplicacionLenguaje();
                            pcApp.PalabrasClaveAplicacionLenguajes.Add(appLen);
                            appLen.ClaveId = pcApp.Id;
                            appLen.LenguajeId = leng.Id;
                            appLen.Traduccion = provincia.Nombre; // x defecto
                        }
                    }

                    EntityMapper.Map(provincia, dbProvincia, "Id");

                    ctx.SaveChanges();
                    tScope.Complete();
                    provincia.Id = dbProvincia.Id;
                }
            }

            return provincia;
        }

        public void EliminarProvinciaDto(ServiceOptions options, int provinciaId)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbProvincia = ctx.DbProvincias.Where(c => c.Id == provinciaId).SingleOrDefault();
                    if (dbProvincia != null)
                    {
                        ctx.DbProvincias.DeleteObject(dbProvincia);
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public List<TipoMensajeBitacora> GetTipoMensajeBitacora(TipoMensajeBitacoraSearch search)
        {
            DateTime now = DateTime.Now;
            List<TipoMensajeBitacora> tipoMensajeList = new List<TipoMensajeBitacora>();
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                IQueryable<DbTipoMensajeBitacora> query = ctx.DbTipoMensajeBitacoras.FilterLogicalRemoved();

                query = query.Where(c => c.EmpresaId == search.EmpresaId);

                if (search.Id.HasValue)
                {
                    query = query.Where(c => c.Id == search.Id.Value);
                }
                else
                {
                    if (search.EsPdv.HasValue)
                    {
                        query = query.Where(c => c.EsPdv == search.EsPdv.Value);
                    }

                    if (!String.IsNullOrEmpty(search.Nombre))
                    {
                        query = query.Where(c => c.Nombre.Contains(search.Nombre));
                    }
                }

                foreach (var dbTipoMensaje in query)
                {
                    TipoMensajeBitacora tipoMensaje = new TipoMensajeBitacora();
                    EntityMapper.Map(dbTipoMensaje, tipoMensaje);
                    tipoMensajeList.Add(tipoMensaje);
                }
            }

            return tipoMensajeList;
        }

        public TipoMensajeBitacora SaveTipoMensajeBitacora(ServiceOptions options, TipoMensajeBitacora tipoMensaje)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbTipoMensaje = ctx.DbTipoMensajeBitacoras.Where(c => c.Id == tipoMensaje.Id).SingleOrDefault();
                    if (dbTipoMensaje == null)
                    {
                        dbTipoMensaje = new DbTipoMensajeBitacora();
                        ctx.DbTipoMensajeBitacoras.AddObject(dbTipoMensaje);
                        dbTipoMensaje.AuditFechaCreacion = now;
                        dbTipoMensaje.AuditUserNameCreacion = options.UserName;
                        dbTipoMensaje.EmpresaId = options.CompanyId;
                    }

                    EntityMapper.Map(tipoMensaje, dbTipoMensaje, "Id");
                    dbTipoMensaje.AuditFechaModificacion = now;
                    dbTipoMensaje.AuditUserNameModificacion = options.UserName;

                    ctx.SaveChanges();
                    tScope.Complete();
                    tipoMensaje.Id = dbTipoMensaje.Id;
                }
            }

            return tipoMensaje;
        }

        public void EliminarTipoMensajeBitacora(ServiceOptions options, int tipoMensajeId)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbTipoMensaje = ctx.DbTipoMensajeBitacoras.Where(c => c.Id == tipoMensajeId).SingleOrDefault();
                    if (dbTipoMensaje == null)
                    {
                        dbTipoMensaje.AuditFechaModificacion = now;
                        dbTipoMensaje.AuditUserNameModificacion = options.UserName;
                        dbTipoMensaje.Removed = true;
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public CompanyConfiguration SaveCompanyConfiguration(ServiceOptions options, CompanyConfiguration companyConfiguration)
        {
            DateTime now = DateTime.Now;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctx = new CrmContactoEntities())
                {
                    var dbEmpresa = ctx.DbEmpresas.Where(c => c.Id == companyConfiguration.CompanyId).SingleOrDefault();

                    dbEmpresa.CssFilePath = companyConfiguration.CssFilePath;
                    dbEmpresa.LogoImgFilePath = companyConfiguration.LogoImgFilePath;

                    // Los key value
                    foreach (var config in companyConfiguration.CompanyConfigurationKeyValueList)
                    {
                        var dbConfigKeyValue = dbEmpresa.EmpresaConfigurations.Where(e => e.ConfigKey == config.Key).SingleOrDefault();
                        dbConfigKeyValue.ConfigValue = config.Value;
                    }

                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }

            return companyConfiguration;
        }

        public SubPuntoDeVenta SaveSubPuntoDeVenta(ServiceOptions options, SubPuntoDeVenta subPuntoDeVenta)
        {
             DateTime now = DateTime.Now;
             using (TransactionScope tScope = new TransactionScope())
             {
                 using (CrmContactoEntities ctx = new CrmContactoEntities())
                 {
                     DbSubPuntoDeVenta dbSubPto = ctx.DbSubPuntoDeVentas.Where(s => s.Id == subPuntoDeVenta.Id).SingleOrDefault();
                     if (dbSubPto == null)
                     {
                         dbSubPto = new DbSubPuntoDeVenta();
                         ctx.DbSubPuntoDeVentas.AddObject(dbSubPto);                         
                     }

                     EntityMapper.Map(subPuntoDeVenta, dbSubPto, "Id");

                     ctx.SaveChanges();
                     tScope.Complete();
                     subPuntoDeVenta.Id = dbSubPto.Id;
                 }
             }

             return subPuntoDeVenta;
        }

        public void RemoveSubPuntoDeVentaFromPdv(ServiceOptions options, int subPuntoDeVentaId)
        {
            using (CrmContactoEntities ctx = new CrmContactoEntities())
            {
                DbSubPuntoDeVenta dbSubPto = ctx.DbSubPuntoDeVentas.Where(s => s.Id == subPuntoDeVentaId).SingleOrDefault();
                if (dbSubPto != null)
                {
                    ctx.DbSubPuntoDeVentas.DeleteObject(dbSubPto);
                    ctx.SaveChanges();                
                }                                
            }
        }
    }
}
